git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* Re: There should be a `.gitbless; file, protecting files from git clean
  2019-01-28  5:05  4% ` Duy Nguyen
@ 2019-01-28  5:24  4%   ` Sebastian Gniazdowski
  0 siblings, 0 replies; 200+ results
From: Sebastian Gniazdowski @ 2019-01-28  5:24 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List

On 28 stycznia 2019 at 06:05:31, Duy Nguyen (pclouds@gmail.com) wrote:
> On Mon, Jan 28, 2019 at 9:54 AM Sebastian Gniazdowski
> wrote:
> >
> > Hello,
> > Could a .gitbless file be a solution? I would list in it, e.g.:
> >
> > TODO
> >
> > and this way be able to use `git -dxf' again. What do you think?
> 
> There's a patch that adds "precious" git attribute [1]. I was going to
> resend once the backup-log [2] got reviewed but I might just send it
> separately to handle the "git clean" case alone.

That would be nice solution. In the email, you ask for a name other than "precious". So maybe "blessed"?

-- 
Sebastian Gniazdowski 
News: https://twitter.com/ZdharmaI
IRC: https://kiwiirc.com/client/chat.freenode.net:+6697/#zplugin
Blog: http://zdharma.org


^ permalink raw reply	[relevance 4%]

* Re: There should be a `.gitbless; file, protecting files from git clean
  @ 2019-01-28  5:05  4% ` Duy Nguyen
  2019-01-28  5:24  4%   ` Sebastian Gniazdowski
  0 siblings, 1 reply; 200+ results
From: Duy Nguyen @ 2019-01-28  5:05 UTC (permalink / raw)
  To: Sebastian Gniazdowski; +Cc: Git Mailing List

On Mon, Jan 28, 2019 at 9:54 AM Sebastian Gniazdowski
<psprint@zdharma.org> wrote:
>
> Hello,
> Keepiing repo clean with `git clean -dxf' is a very pleasant experience. However, ability to use it ends when one gets untracked but *wanted* files in the repo, like an untracked TODO.
>
> Could a .gitbless file be a solution? I would list in it, e.g.:
>
> TODO
>
> and this way be able to use `git -dxf' again. What do you think?

There's a patch that adds "precious" git attribute [1]. I was going to
resend once the backup-log [2] got reviewed but I might just send it
separately to handle the "git clean" case alone.

[1] https://public-inbox.org/git/20181111095254.30473-1-pclouds@gmail.com/
[2] https://public-inbox.org/git/20181209104419.12639-1-pclouds@gmail.com/

>
> --
> Sebastian Gniazdowski
> News: https://twitter.com/ZdharmaI
> IRC: https://kiwiirc.com/client/chat.freenode.net:+6697/#zplugin
> Blog: http://zdharma.org
>


-- 
Duy

^ permalink raw reply	[relevance 4%]

* Re: [PATCH 01/10] doc: about submodule support with multiple worktrees
  2019-01-16 10:31  3% ` [PATCH 01/10] doc: about submodule support with multiple worktrees Nguyễn Thái Ngọc Duy
@ 2019-01-16 22:06  0%   ` Stefan Beller
  0 siblings, 0 replies; 200+ results
From: Stefan Beller @ 2019-01-16 22:06 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Tomasz Śniatowski, Jonathan Nieder, Marc Branchaud,
	Junio C Hamano

> The third problem is a big and complicaed one. Submodule clones

complicated

> (inside the superproject) are per-worktree. So if you have two
> worktrees, and these have one submodule, you need space for _two_
> clones. This is definitely not elegant. The tenative plan is to move

tentative?

> clones from $GIT_COMMON_DIR/worktrees/X/modules to
> $GIT_COMMON_DIR/common/modules.

... from the submodule side of things this is big problem,
as the submodule is usually assumed at $GIT_DIR/modules/<name>
(I think we have not been strict in $GIT_DIR $GIT_COMMON_DIR
in the submodule code)

So the plan is to neither use
$GIT_COMMON_DIR/worktrees/X/modules/Y
$GIT_COMMON_DIR/modules/Y/worktrees/X
but to create a new third location at
$GIT_COMMON_DIR/common/modules
to which either new submodule worktrees
or superproject worktrees that happen to have this submodule
can point to?

>
> The latter directory is shared across all worktrees. Once we keep the
> clone in a common place, the submodule's worktree can be created and
> managed with git-worktree[1].

So even when the user has never heard of worktrees, the internal structure
will be worktree oriented, the common dir in common/modules/Y and in
$GIT_DIR/modules/Y we could just have a worktree git dir?

> Another good point about this approach is we could finally safely
> allow "git worktree remove" to work with submodules. With current
> solution, removing $GIT_COMMON_DIR/worktrees/X directory means also
> removing potentially precious clones inside the "modules" subdir.

yup, very sensible.

I like this approach very much.

^ permalink raw reply	[relevance 0%]

* [PATCH 01/10] doc: about submodule support with multiple worktrees
  @ 2019-01-16 10:31  3% ` Nguyễn Thái Ngọc Duy
  2019-01-16 22:06  0%   ` Stefan Beller
  0 siblings, 1 reply; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2019-01-16 10:31 UTC (permalink / raw)
  To: git
  Cc: Stefan Beller, tsniatowski, Jonathan Nieder, marcnarc,
	Junio C Hamano, Nguyễn Thái Ngọc Duy

This lays out the very first step of making multiple worktrees and
submodules work together.

The first problem is git-submodule keeps per-worktree config in
$GIT_DIR/config, which is shared for all worktrees. This series makes
git-submodule use extensions.worktreeConfig and write submodule.* to
config.worktree instead.

The rest goes on and on about the remaining problems. But let's talk a
bit more about solving the first problem. Since it relies on the
experimental extensions.worktreeConfig, this support is of course also
experimental. On the other hand, submodules have never really worked
with multi worktrees before, this change can't bite anybody.

Second problem. That is about multiple worktrees at superproject
level. At submodule level, we still can't have multiple worktrees
because git-submodule writes to submodule's "config" file
(again). Fixing this is not particularly hard. Absorbing submodule's
git dir takes some work but is feasible. This could be addressed soon
in the future.

The third problem is a big and complicaed one. Submodule clones
(inside the superproject) are per-worktree. So if you have two
worktrees, and these have one submodule, you need space for _two_
clones. This is definitely not elegant. The tenative plan is to move
clones from $GIT_COMMON_DIR/worktrees/X/modules to
$GIT_COMMON_DIR/common/modules.

The latter directory is shared across all worktrees. Once we keep the
clone in a common place, the submodule's worktree can be created and
managed with git-worktree[1].

Another good point about this approach is we could finally safely
allow "git worktree remove" to work with submodules. With current
solution, removing $GIT_COMMON_DIR/worktrees/X directory means also
removing potentially precious clones inside the "modules" subdir.

But whether we can do this depends on:

- if we need separate ref namespace for submodule on each worktree

- how does submodule's worktrees (remember the second problem)
  interact these worktrees

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt  |  8 ++++++++
 Documentation/gitsubmodules.txt | 17 +++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index aae8e1d8b2..3510fd5331 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -267,6 +267,14 @@ configuration that you do not want to share to all working trees:
  - `core.sparseCheckout` is recommended per working tree, unless you
    are sure you always use sparse checkout for all working trees.
 
+ - Most configuration variables under `submodule` group in superproject
+   should not be shared.
++
+------------
+$ git config --local --move-to --worktree submodule.active
+$ git config --local --move-to-regexp --worktree 'submodule\..*\..*'
+------------
+
 DETAILS
 -------
 Each linked working tree has a private sub-directory in the repository's
diff --git a/Documentation/gitsubmodules.txt b/Documentation/gitsubmodules.txt
index 57999e9f36..d91817b45d 100644
--- a/Documentation/gitsubmodules.txt
+++ b/Documentation/gitsubmodules.txt
@@ -222,6 +222,23 @@ submodule active pathspec, which specifies that any submodule
 starting with 'b' except 'baz' are also active, regardless of the
 presence of the .url field.
 
+MULTIPLE WORKING TREE SUPPORT
+-----------------------------
+When you have more than one working tree, created by
+linkgit:git-worktree[1], submodules will not work on any working tree
+until `extensions.worktreeConfig` is enabled. Since this config
+affects more than just submodules, please see "CONFIGURATION FILE"
+section for more information before turning it on.
+
+Once on, submodules can be added in any working tree. The submodule
+itself though cannot have more than one working tree.
+
+When submodules are created in a working tree, their git directory is
+also per-worktree, e.g. inside
+'$GIT_COMMON_DIR/worktrees/<worktree>/modules' and not shared with
+other working trees. This means if you have the same submodule on
+different working trees, you need disk space for multiple clones.
+
 Workflow for a third party library
 ----------------------------------
 
-- 
2.20.0.482.g66447595a7


^ permalink raw reply related	[relevance 3%]

* [PATCH v3] worktree: allow to (re)move worktrees with uninitialized submodules
  2018-12-16 14:46  3% ` [PATCH v2] " Nguyễn Thái Ngọc Duy
  2019-01-04 22:51  0%   ` Junio C Hamano
@ 2019-01-05  5:08  3%   ` Nguyễn Thái Ngọc Duy
  1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2019-01-05  5:08 UTC (permalink / raw)
  To: pclouds; +Cc: git, sunshine, Junio C Hamano

Uninitialized submodules have nothing valueable for us to be worried
about. They are just SHA-1. Let "worktree remove" and "worktree move"
continue in this case so that people can still use multiple worktrees
on repos with optional submodules that are never populated, like
sha1collisiondetection in git.git when checked out by doc-diff script.

Note that for "worktree remove", it is possible that a user
initializes a submodule (*), makes some commits (but not push), then
deinitializes it. At that point, the submodule is unpopulated, but the
precious new commits are still in

    $GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule>

directory and we should not allow removing the worktree or we lose
those commits forever. The new directory check is added to prevent
this.

(*) yes they are screwed anyway by doing this since "git submodule"
    would add submodule.* in $GIT_COMMON_DIR/config, which is shared
    across multiple worktrees. But it does not mean we let them be
    screwed even more.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 v3 adds tests. This test file is being renamed by
 tg/checkout-no-overlay but it seems rename is handled correctly, no
 merge conflicts on 'pu'.

 builtin/worktree.c       | 29 +++++++++++++++++++++++------
 t/t2028-worktree-move.sh | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 60 insertions(+), 6 deletions(-)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 5e84026177..3f9907fcc9 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -9,6 +9,7 @@
 #include "refs.h"
 #include "run-command.h"
 #include "sigchain.h"
+#include "submodule.h"
 #include "refs.h"
 #include "utf8.h"
 #include "worktree.h"
@@ -724,20 +725,36 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
 static void validate_no_submodules(const struct worktree *wt)
 {
 	struct index_state istate = { NULL };
+	struct strbuf path = STRBUF_INIT;
 	int i, found_submodules = 0;
 
-	if (read_index_from(&istate, worktree_git_path(wt, "index"),
-			    get_worktree_git_dir(wt)) > 0) {
+	if (is_directory(worktree_git_path(wt, "modules"))) {
+		/*
+		 * There could be false positives, e.g. the "modules"
+		 * directory exists but is empty. But it's a rare case and
+		 * this simpler check is probably good enough for now.
+		 */
+		found_submodules = 1;
+	} else if (read_index_from(&istate, worktree_git_path(wt, "index"),
+				   get_worktree_git_dir(wt)) > 0) {
 		for (i = 0; i < istate.cache_nr; i++) {
 			struct cache_entry *ce = istate.cache[i];
+			int err;
 
-			if (S_ISGITLINK(ce->ce_mode)) {
-				found_submodules = 1;
-				break;
-			}
+			if (!S_ISGITLINK(ce->ce_mode))
+				continue;
+
+			strbuf_reset(&path);
+			strbuf_addf(&path, "%s/%s", wt->path, ce->name);
+			if (!is_submodule_populated_gently(path.buf, &err))
+				continue;
+
+			found_submodules = 1;
+			break;
 		}
 	}
 	discard_index(&istate);
+	strbuf_release(&path);
 
 	if (found_submodules)
 		die(_("working trees containing submodules cannot be moved or removed"));
diff --git a/t/t2028-worktree-move.sh b/t/t2028-worktree-move.sh
index 33c0337733..939d18d728 100755
--- a/t/t2028-worktree-move.sh
+++ b/t/t2028-worktree-move.sh
@@ -112,6 +112,26 @@ test_expect_success 'move locked worktree (force)' '
 	git worktree move --force --force flump ploof
 '
 
+test_expect_success 'move a repo with uninitialized submodule' '
+	git init withsub &&
+	(
+		cd withsub &&
+		test_commit initial &&
+		git submodule add "$PWD"/.git sub &&
+		git commit -m withsub &&
+		git worktree add second HEAD &&
+		git worktree move second third
+	)
+'
+
+test_expect_success 'not move a repo with initialized submodule' '
+	(
+		cd withsub &&
+		git -C third submodule update &&
+		test_must_fail git worktree move third forth
+	)
+'
+
 test_expect_success 'remove main worktree' '
 	test_must_fail git worktree remove .
 '
@@ -185,4 +205,21 @@ test_expect_success 'remove cleans up .git/worktrees when empty' '
 	)
 '
 
+test_expect_success 'remove a repo with uninitialized submodule' '
+	(
+		cd withsub &&
+		git worktree add to-remove HEAD &&
+		git worktree remove to-remove
+	)
+'
+
+test_expect_success 'not remove a repo with initialized submodule' '
+	(
+		cd withsub &&
+		git worktree add to-remove HEAD &&
+		git -C to-remove submodule update &&
+		test_must_fail git worktree remove to-remove
+	)
+'
+
 test_done
-- 
2.20.0.482.g66447595a7


^ permalink raw reply related	[relevance 3%]

* Re: [PATCH v2] worktree: allow to (re)move worktrees with uninitialized submodules
  2018-12-16 14:46  3% ` [PATCH v2] " Nguyễn Thái Ngọc Duy
@ 2019-01-04 22:51  0%   ` Junio C Hamano
  2019-01-05  5:08  3%   ` [PATCH v3] " Nguyễn Thái Ngọc Duy
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2019-01-04 22:51 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: sunshine, git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> Uninitialized submodules have nothing valueable for us to be worried
> about. They are just SHA-1. Let "worktree remove" and "worktree move"
> continue in this case so that people can still use multiple worktrees
> on repos with optional submodules that are never populated, like
> sha1collisiondetection in git.git when checked out by doc-diff script.
>
> Note that for "worktree remove", it is possible that a user
> initializes a submodule (*), makes some commits (but not push), then
> deinitializes it. At that point, the submodule is unpopulated, but the
> precious new commits are still in
>
>     $GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule>
>
> directory and we should not allow removing the worktree or we lose
> those commits forever. The new directory check is added to prevent
> this.
>
> (*) yes they are screwed anyway by doing this since "git submodule"
>     would add submodule.* in $GIT_COMMON_DIR/config, which is shared
>     across multiple worktrees. But it does not mean we let them be
>     screwed even more.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  Fixed Eric's comment. I was a bit annoyed by the duplicate die() too
>  but didn't think of adding "else" in front of "if (read_index"
>
>  builtin/worktree.c | 29 +++++++++++++++++++++++------
>  1 file changed, 23 insertions(+), 6 deletions(-)

Is this a fair description for this 1-patch topic?

	"git worktree remove" and "git worktree move" failed to work
	when there is an uninitialized submodule, which has been fixed.

If so, can we have a test case to cover this fix?

Thanks.

> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 5e84026177..3f9907fcc9 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -9,6 +9,7 @@
>  #include "refs.h"
>  #include "run-command.h"
>  #include "sigchain.h"
> +#include "submodule.h"
>  #include "refs.h"
>  #include "utf8.h"
>  #include "worktree.h"
> @@ -724,20 +725,36 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
>  static void validate_no_submodules(const struct worktree *wt)
>  {
>  	struct index_state istate = { NULL };
> +	struct strbuf path = STRBUF_INIT;
>  	int i, found_submodules = 0;
>  
> -	if (read_index_from(&istate, worktree_git_path(wt, "index"),
> -			    get_worktree_git_dir(wt)) > 0) {
> +	if (is_directory(worktree_git_path(wt, "modules"))) {
> +		/*
> +		 * There could be false positives, e.g. the "modules"
> +		 * directory exists but is empty. But it's a rare case and
> +		 * this simpler check is probably good enough for now.
> +		 */
> +		found_submodules = 1;
> +	} else if (read_index_from(&istate, worktree_git_path(wt, "index"),
> +				   get_worktree_git_dir(wt)) > 0) {
>  		for (i = 0; i < istate.cache_nr; i++) {
>  			struct cache_entry *ce = istate.cache[i];
> +			int err;
>  
> -			if (S_ISGITLINK(ce->ce_mode)) {
> -				found_submodules = 1;
> -				break;
> -			}
> +			if (!S_ISGITLINK(ce->ce_mode))
> +				continue;
> +
> +			strbuf_reset(&path);
> +			strbuf_addf(&path, "%s/%s", wt->path, ce->name);
> +			if (!is_submodule_populated_gently(path.buf, &err))
> +				continue;
> +
> +			found_submodules = 1;
> +			break;
>  		}
>  	}
>  	discard_index(&istate);
> +	strbuf_release(&path);
>  
>  	if (found_submodules)
>  		die(_("working trees containing submodules cannot be moved or removed"));

^ permalink raw reply	[relevance 0%]

* [PATCH v2] worktree: allow to (re)move worktrees with uninitialized submodules
  2018-12-16 12:12  4% [PATCH] worktree: allow to (re)move worktrees with uninitialized submodules Nguyễn Thái Ngọc Duy
@ 2018-12-16 14:46  3% ` Nguyễn Thái Ngọc Duy
  2019-01-04 22:51  0%   ` Junio C Hamano
  2019-01-05  5:08  3%   ` [PATCH v3] " Nguyễn Thái Ngọc Duy
  0 siblings, 2 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-12-16 14:46 UTC (permalink / raw)
  To: pclouds, sunshine; +Cc: git

Uninitialized submodules have nothing valueable for us to be worried
about. They are just SHA-1. Let "worktree remove" and "worktree move"
continue in this case so that people can still use multiple worktrees
on repos with optional submodules that are never populated, like
sha1collisiondetection in git.git when checked out by doc-diff script.

Note that for "worktree remove", it is possible that a user
initializes a submodule (*), makes some commits (but not push), then
deinitializes it. At that point, the submodule is unpopulated, but the
precious new commits are still in

    $GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule>

directory and we should not allow removing the worktree or we lose
those commits forever. The new directory check is added to prevent
this.

(*) yes they are screwed anyway by doing this since "git submodule"
    would add submodule.* in $GIT_COMMON_DIR/config, which is shared
    across multiple worktrees. But it does not mean we let them be
    screwed even more.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Fixed Eric's comment. I was a bit annoyed by the duplicate die() too
 but didn't think of adding "else" in front of "if (read_index"

 builtin/worktree.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 5e84026177..3f9907fcc9 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -9,6 +9,7 @@
 #include "refs.h"
 #include "run-command.h"
 #include "sigchain.h"
+#include "submodule.h"
 #include "refs.h"
 #include "utf8.h"
 #include "worktree.h"
@@ -724,20 +725,36 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
 static void validate_no_submodules(const struct worktree *wt)
 {
 	struct index_state istate = { NULL };
+	struct strbuf path = STRBUF_INIT;
 	int i, found_submodules = 0;
 
-	if (read_index_from(&istate, worktree_git_path(wt, "index"),
-			    get_worktree_git_dir(wt)) > 0) {
+	if (is_directory(worktree_git_path(wt, "modules"))) {
+		/*
+		 * There could be false positives, e.g. the "modules"
+		 * directory exists but is empty. But it's a rare case and
+		 * this simpler check is probably good enough for now.
+		 */
+		found_submodules = 1;
+	} else if (read_index_from(&istate, worktree_git_path(wt, "index"),
+				   get_worktree_git_dir(wt)) > 0) {
 		for (i = 0; i < istate.cache_nr; i++) {
 			struct cache_entry *ce = istate.cache[i];
+			int err;
 
-			if (S_ISGITLINK(ce->ce_mode)) {
-				found_submodules = 1;
-				break;
-			}
+			if (!S_ISGITLINK(ce->ce_mode))
+				continue;
+
+			strbuf_reset(&path);
+			strbuf_addf(&path, "%s/%s", wt->path, ce->name);
+			if (!is_submodule_populated_gently(path.buf, &err))
+				continue;
+
+			found_submodules = 1;
+			break;
 		}
 	}
 	discard_index(&istate);
+	strbuf_release(&path);
 
 	if (found_submodules)
 		die(_("working trees containing submodules cannot be moved or removed"));
-- 
2.20.0.482.g66447595a7


^ permalink raw reply related	[relevance 3%]

* [PATCH] worktree: allow to (re)move worktrees with uninitialized submodules
@ 2018-12-16 12:12  4% Nguyễn Thái Ngọc Duy
  2018-12-16 14:46  3% ` [PATCH v2] " Nguyễn Thái Ngọc Duy
  0 siblings, 1 reply; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-12-16 12:12 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Uninitialized submodules have nothing valueable for us to be worried
about. They are just SHA-1. Let "worktree remove" and "worktree move"
continue in this case so that people can still use multiple worktrees
on repos with optional submodules that are never populated, like
sha1collisiondetection in git.git when checked out by doc-diff script.

Note that for "worktree remove", it is possible that a user
initializes a submodule (*), makes some commits (but not push), then
deinitializes it. At that point, the submodule is unpopulated, but the
precious new commits are still in

    $GIT_COMMON_DIR/worktrees/<worktree>/modules/<submodule>

directory and we should not allow removing the worktree or we lose
those commits forever. The new directory check is added to prevent
this.

(*) yes they are screwed anyway by doing this since "git submodule"
    would add submodule.* in $GIT_COMMON_DIR/config, which is shared
    across multiple worktrees. But it does not mean we let them be
    screwed even more.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/worktree.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 5e84026177..af03b83a26 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -9,6 +9,7 @@
 #include "refs.h"
 #include "run-command.h"
 #include "sigchain.h"
+#include "submodule.h"
 #include "refs.h"
 #include "utf8.h"
 #include "worktree.h"
@@ -724,20 +725,32 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
 static void validate_no_submodules(const struct worktree *wt)
 {
 	struct index_state istate = { NULL };
+	struct strbuf path = STRBUF_INIT;
 	int i, found_submodules = 0;
 
+	if (is_directory(worktree_git_path(wt, "modules")))
+		die(_("working trees containing submodules cannot be moved or removed"));
+
 	if (read_index_from(&istate, worktree_git_path(wt, "index"),
 			    get_worktree_git_dir(wt)) > 0) {
 		for (i = 0; i < istate.cache_nr; i++) {
 			struct cache_entry *ce = istate.cache[i];
+			int err;
 
-			if (S_ISGITLINK(ce->ce_mode)) {
-				found_submodules = 1;
-				break;
-			}
+			if (!S_ISGITLINK(ce->ce_mode))
+				continue;
+
+			strbuf_reset(&path);
+			strbuf_addf(&path, "%s/%s", wt->path, ce->name);
+			if (!is_submodule_populated_gently(path.buf, &err))
+				continue;
+
+			found_submodules = 1;
+			break;
 		}
 	}
 	discard_index(&istate);
+	strbuf_release(&path);
 
 	if (found_submodules)
 		die(_("working trees containing submodules cannot be moved or removed"));
-- 
2.20.0.482.g66447595a7


^ permalink raw reply related	[relevance 4%]

* [PATCH 24/24] FIXME
  2018-12-09 10:43  3% [RFC PATCH 00/24] Add backup log Nguyễn Thái Ngọc Duy
  2018-12-09 10:44  7% ` [PATCH 19/24] unpack-trees.c: keep backup of ignored files being overwritten Nguyễn Thái Ngọc Duy
@ 2018-12-09 10:44  6% ` Nguyễn Thái Ngọc Duy
  1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-12-09 10:44 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-backup-log.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/git-backup-log.txt b/Documentation/git-backup-log.txt
index 98998156c1..fe03726337 100644
--- a/Documentation/git-backup-log.txt
+++ b/Documentation/git-backup-log.txt
@@ -41,6 +41,8 @@ following commands will save backups:
   `--hard` or linkgit:git-am[1] and linkgit:git-rebase[1] with
   `--skip` or `--abort` will make a backup before overwriting non
   up-to-date files.
+- FIXME perhaps `git checkout <paths>` only makes backups on
+  "precious" paths only?
 
 Backups are split in three groups, changes related in the index, in
 working directory or in $GIT_DIR. These can be selected with `--id`
-- 
2.20.0.rc2.486.g9832c05c3d


^ permalink raw reply related	[relevance 6%]

* [PATCH 19/24] unpack-trees.c: keep backup of ignored files being overwritten
  2018-12-09 10:43  3% [RFC PATCH 00/24] Add backup log Nguyễn Thái Ngọc Duy
@ 2018-12-09 10:44  7% ` Nguyễn Thái Ngọc Duy
  2018-12-09 10:44  6% ` [PATCH 24/24] FIXME Nguyễn Thái Ngọc Duy
  1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-12-09 10:44 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Ignored files are usually machine generated (e.g. *.o) and not worth
keeping, so when a merge or branch switch happens and need to
overwrite them, we just go ahead and do it. Occasionally though
ignored files _can_ have valuable content.

We will likely have a separate mechanism to protect these "precious"
ignored files, but a surprise is still a surprise. Keep a backup of
ignored files when they are overwritten (until we are explicitly told
"rubbish" by said mechanism). This lets the user recover the content
and start telling git that the file is precious so it won't happen
again.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/checkout.c    |  2 ++
 merge.c               |  2 ++
 t/t2080-backup-log.sh | 21 ++++++++++++
 unpack-trees.c        | 77 +++++++++++++++++++++++++++++++++++--------
 unpack-trees.h        |  3 ++
 5 files changed, 92 insertions(+), 13 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index acdafc6e4c..b5e27a5f6d 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -620,6 +620,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
 			topts.dir = xcalloc(1, sizeof(*topts.dir));
 			topts.dir->flags |= DIR_SHOW_IGNORED;
 			setup_standard_excludes(topts.dir);
+			repo_config_get_bool(the_repository, "core.backupLog",
+					     &topts.keep_backup);
 		}
 		tree = parse_tree_indirect(old_branch_info->commit ?
 					   &old_branch_info->commit->object.oid :
diff --git a/merge.c b/merge.c
index 91008f7602..9f20305d7a 100644
--- a/merge.c
+++ b/merge.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "config.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "lockfile.h"
@@ -85,6 +86,7 @@ int checkout_fast_forward(struct repository *r,
 		dir.flags |= DIR_SHOW_IGNORED;
 		setup_standard_excludes(&dir);
 		opts.dir = &dir;
+		repo_config_get_bool(r, "core.backupLog", &opts.keep_backup);
 	}
 
 	opts.head_idx = 1;
diff --git a/t/t2080-backup-log.sh b/t/t2080-backup-log.sh
index 710df1ec8b..a283528912 100755
--- a/t/t2080-backup-log.sh
+++ b/t/t2080-backup-log.sh
@@ -190,4 +190,25 @@ test_expect_success 'deleted reflog is kept' '
 	grep ^$OLD .git/common/gitdir.bkl
 '
 
+test_expect_success 'overwritten ignored file is backed up' '
+	git init overwrite-ignore &&
+	(
+		cd overwrite-ignore &&
+		echo ignored-overwritten >ignored &&
+		NEW=$(git hash-object ignored) &&
+		git add ignored &&
+		git commit -m ignored &&
+		git rm --cached ignored &&
+		echo /ignored >.gitignore &&
+		git add .gitignore &&
+		git commit -m first-commit-no-ignored &&
+		echo precious >ignored &&
+		OLD=$(git hash-object ignored) &&
+		test_tick &&
+		git -c core.backupLog=true checkout --detach HEAD^ &&
+		echo "$OLD $NEW $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $test_tick -0700	ignored" >expected &&
+		test_cmp expected .git/worktree.bkl
+	)
+'
+
 test_done
diff --git a/unpack-trees.c b/unpack-trees.c
index 7570df481b..8d7273af2b 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1,6 +1,7 @@
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "argv-array.h"
+#include "backup-log.h"
 #include "repository.h"
 #include "config.h"
 #include "dir.h"
@@ -191,6 +192,23 @@ void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
 	memset(opts->msgs, 0, sizeof(opts->msgs));
 }
 
+static void make_backup(const struct cache_entry *ce,
+			const struct object_id *old_hash,
+			const struct object_id *new_hash,
+			struct unpack_trees_options *o)
+{
+	struct object_id null_hash;
+
+	if (!o->keep_backup || is_null_oid(old_hash))
+		return;
+
+	if (!new_hash) {
+		oidclr(&null_hash);
+		new_hash = &null_hash;
+	}
+	bkl_append(&o->backup_log, ce->name, old_hash, new_hash);
+}
+
 static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
 			 unsigned int set, unsigned int clear)
 {
@@ -462,6 +480,9 @@ static int check_updates(struct unpack_trees_options *o)
 	if (o->clone)
 		report_collided_checkout(index);
 
+	if (o->backup_log.len)
+		bkl_write(git_path("worktree.bkl"), &o->backup_log);
+
 	trace_performance_leave("check_updates");
 	return errs != 0;
 }
@@ -1460,7 +1481,8 @@ static void mark_new_skip_worktree(struct exclude_list *el,
 
 static int verify_absent(const struct cache_entry *,
 			 enum unpack_trees_error_types,
-			 struct unpack_trees_options *);
+			 struct unpack_trees_options *,
+			 struct object_id *);
 /*
  * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the
  * resulting index, -2 on failure to reflect the changes to the work tree.
@@ -1489,6 +1511,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 		free(sparse);
 	}
 
+	strbuf_init(&o->backup_log, 0);
+	if (!o->update)
+		o->keep_backup = 0;
+
 	memset(&o->result, 0, sizeof(o->result));
 	o->result.initialized = 1;
 	o->result.timestamp.sec = o->src_index->timestamp.sec;
@@ -1596,7 +1622,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 			 * correct CE_NEW_SKIP_WORKTREE
 			 */
 			if (ce->ce_flags & CE_ADDED &&
-			    verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
+			    verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o, NULL)) {
 				if (!o->show_all_errors)
 					goto return_failed;
 				ret = -1;
@@ -1646,6 +1672,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 	o->src_index = NULL;
 
 done:
+	strbuf_release(&o->backup_log);
 	trace_performance_leave("unpack_trees");
 	clear_exclude_list(&el);
 	return ret;
@@ -1880,7 +1907,8 @@ static int icase_exists(struct unpack_trees_options *o, const char *name, int le
 static int check_ok_to_remove(const char *name, int len, int dtype,
 			      const struct cache_entry *ce, struct stat *st,
 			      enum unpack_trees_error_types error_type,
-			      struct unpack_trees_options *o)
+			      struct unpack_trees_options *o,
+			      struct object_id *old_hash)
 {
 	const struct cache_entry *result;
 
@@ -1895,12 +1923,16 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
 		return 0;
 
 	if (o->dir &&
-	    is_excluded(o->dir, o->src_index, name, &dtype))
+	    is_excluded(o->dir, o->src_index, name, &dtype)) {
+		if (o->keep_backup && old_hash)
+			index_path(NULL, old_hash, name, st,
+				   HASH_WRITE_OBJECT);
 		/*
 		 * ce->name is explicitly excluded, so it is Ok to
 		 * overwrite it.
 		 */
 		return 0;
+	}
 	if (S_ISDIR(st->st_mode)) {
 		/*
 		 * We are checking out path "foo" and
@@ -1935,7 +1967,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
  */
 static int verify_absent_1(const struct cache_entry *ce,
 			   enum unpack_trees_error_types error_type,
-			   struct unpack_trees_options *o)
+			   struct unpack_trees_options *o,
+			   struct object_id *old_hash)
 {
 	int len;
 	struct stat st;
@@ -1960,7 +1993,7 @@ static int verify_absent_1(const struct cache_entry *ce,
 								NULL, o);
 			else
 				ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL,
-							 &st, error_type, o);
+							 &st, error_type, o, old_hash);
 		}
 		free(path);
 		return ret;
@@ -1975,17 +2008,20 @@ static int verify_absent_1(const struct cache_entry *ce,
 
 		return check_ok_to_remove(ce->name, ce_namelen(ce),
 					  ce_to_dtype(ce), ce, &st,
-					  error_type, o);
+					  error_type, o, old_hash);
 	}
 }
 
 static int verify_absent(const struct cache_entry *ce,
 			 enum unpack_trees_error_types error_type,
-			 struct unpack_trees_options *o)
+			 struct unpack_trees_options *o,
+			 struct object_id *old_hash)
 {
+	if (o->keep_backup && old_hash)
+		oidclr(old_hash);
 	if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
 		return 0;
-	return verify_absent_1(ce, error_type, o);
+	return verify_absent_1(ce, error_type, o, old_hash);
 }
 
 static int verify_absent_sparse(const struct cache_entry *ce,
@@ -1996,7 +2032,7 @@ static int verify_absent_sparse(const struct cache_entry *ce,
 	if (orphaned_error == ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN)
 		orphaned_error = ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN;
 
-	return verify_absent_1(ce, orphaned_error, o);
+	return verify_absent_1(ce, orphaned_error, o, NULL);
 }
 
 static int merged_entry(const struct cache_entry *ce,
@@ -2007,6 +2043,8 @@ static int merged_entry(const struct cache_entry *ce,
 	struct cache_entry *merge = dup_cache_entry(ce, &o->result);
 
 	if (!old) {
+		struct object_id old_hash;
+
 		/*
 		 * New index entries. In sparse checkout, the following
 		 * verify_absent() will be delayed until after
@@ -2023,10 +2061,15 @@ static int merged_entry(const struct cache_entry *ce,
 		merge->ce_flags |= CE_NEW_SKIP_WORKTREE;
 
 		if (verify_absent(merge,
-				  ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
+				  ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN,
+				  o, &old_hash)) {
 			discard_cache_entry(merge);
 			return -1;
 		}
+		if (o->keep_backup)
+			bkl_append(&o->backup_log, merge->name,
+				   &old_hash, &merge->oid);
+
 		invalidate_ce_path(merge, o);
 
 		if (submodule_from_ce(ce)) {
@@ -2083,8 +2126,12 @@ static int deleted_entry(const struct cache_entry *ce,
 {
 	/* Did it exist in the index? */
 	if (!old) {
-		if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
+		struct object_id old_hash;
+
+		if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED,
+				  o, &old_hash))
 			return -1;
+		make_backup(ce, &old_hash, NULL, o);
 		return 0;
 	}
 	if (!(old->ce_flags & CE_CONFLICTED) && verify_uptodate(old, o))
@@ -2236,8 +2283,12 @@ int threeway_merge(const struct cache_entry * const *stages,
 			if (index)
 				return deleted_entry(index, index, o);
 			if (ce && !head_deleted) {
-				if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
+				struct object_id old_hash;
+
+				if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED,
+						  o, &old_hash))
 					return -1;
+				make_backup(ce, &old_hash, NULL, o);
 			}
 			return 0;
 		}
diff --git a/unpack-trees.h b/unpack-trees.h
index 0135080a7b..e2a64e2401 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -60,6 +60,7 @@ struct unpack_trees_options {
 		     exiting_early,
 		     show_all_errors,
 		     dry_run;
+	int keep_backup;
 	const char *prefix;
 	int cache_bottom;
 	struct dir_struct *dir;
@@ -83,6 +84,8 @@ struct unpack_trees_options {
 	struct index_state *src_index;
 	struct index_state result;
 
+	struct strbuf backup_log;
+
 	struct exclude_list *el; /* for internal use */
 };
 
-- 
2.20.0.rc2.486.g9832c05c3d


^ permalink raw reply related	[relevance 7%]

* [RFC PATCH 00/24] Add backup log
@ 2018-12-09 10:43  3% Nguyễn Thái Ngọc Duy
  2018-12-09 10:44  7% ` [PATCH 19/24] unpack-trees.c: keep backup of ignored files being overwritten Nguyễn Thái Ngọc Duy
  2018-12-09 10:44  6% ` [PATCH 24/24] FIXME Nguyễn Thái Ngọc Duy
  0 siblings, 2 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-12-09 10:43 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

"Backup log" is similar to reflog. But instead of keeping track of ref
changes, it keeps track of file content changes. These could be from
the index (e.g. "git add" replacing something in the index), worktree
("git reset --hard" deleting everything) or in gitdir ("git config
--edit", or deleted reflog).

Backup log, when enabled, keeps the backup versions so you can undo if
needed. Head for 01/24 to have a better picture what it does, when
backups are made... This series adds a new plumbing command 'git
backup-log' to manage these backups.

A couple things left to do:

- high level UI design, including maybe extended SHA-1 syntax
- whether "git checkout <paths>" should keep backups. I think doing it
  unconditionally may be too much, but maybe keep backups of files
  with "precious" attribute on
- a UI to edit $GIT_DIR/info/excludes and gitattributes so we can make
  backups of them
- whether we should keep command causing the changes in the backup log
  (e.g. this change is made by git-add, that one git-rebase...).
  Reflog has this. I did not add it because it complicates the parsing
  a bit and not sure if it's worth it.

Nguyễn Thái Ngọc Duy (24):
  doc: introduce new "backup log" concept
  backup-log: add "update" subcommand
  read-cache.c: new flag for add_index_entry() to write to backup log
  add: support backup log
  update-index: support backup log with --keep-backup
  commit: support backup log
  apply: support backup log with --keep-backup
  add--interactive: support backup log
  backup-log.c: add API for walking backup log
  backup-log: add cat command
  backup-log: add diff command
  backup-log: add log command
  backup-log: add prune command
  gc: prune backup logs
  backup-log: keep all blob references around
  sha1-file.c: let index_path() accept NULL istate
  config --edit: support backup log
  refs: keep backup of deleted reflog
  unpack-trees.c: keep backup of ignored files being overwritten
  reset --hard: keep backup of overwritten files
  checkout -f: keep backup of overwritten files
  am: keep backup of overwritten files on --skip or --abort
  rebase: keep backup of overwritten files on --skip or --abort
  FIXME

 .gitignore                         |   1 +
 Documentation/config/core.txt      |   5 +
 Documentation/git-apply.txt        |   3 +
 Documentation/git-backup-log.txt   | 109 ++++++++
 Documentation/git-update-index.txt |   3 +
 Makefile                           |   2 +
 apply.c                            |  38 ++-
 apply.h                            |   1 +
 backup-log.c                       | 388 +++++++++++++++++++++++++++++
 backup-log.h                       |  38 +++
 builtin.h                          |   1 +
 builtin/add.c                      |   5 +
 builtin/am.c                       |   3 +
 builtin/backup-log.c               | 371 +++++++++++++++++++++++++++
 builtin/checkout.c                 |   4 +
 builtin/commit.c                   |  16 +-
 builtin/config.c                   |  27 +-
 builtin/gc.c                       |   3 +
 builtin/pack-objects.c             |   9 +-
 builtin/rebase.c                   |   6 +-
 builtin/repack.c                   |   1 +
 builtin/reset.c                    |   2 +
 builtin/update-index.c             |   7 +
 cache.h                            |   2 +
 command-list.txt                   |   1 +
 git-add--interactive.perl          |  14 +-
 git.c                              |   1 +
 merge-recursive.c                  |   2 +-
 merge.c                            |   2 +
 parse-options.c                    |   2 +-
 reachable.c                        |   3 +
 read-cache.c                       |  49 +++-
 refs/files-backend.c               |  32 +++
 revision.c                         |   3 +
 sha1-file.c                        |   8 +-
 t/t2080-backup-log.sh              | 228 +++++++++++++++++
 unpack-trees.c                     | 143 +++++++++--
 unpack-trees.h                     |   6 +-
 38 files changed, 1488 insertions(+), 51 deletions(-)
 create mode 100644 Documentation/git-backup-log.txt
 create mode 100644 backup-log.c
 create mode 100644 backup-log.h
 create mode 100644 builtin/backup-log.c
 create mode 100755 t/t2080-backup-log.sh

-- 
2.20.0.rc2.486.g9832c05c3d


^ permalink raw reply	[relevance 3%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-27 12:55 10%                     ` Jacob Keller
  2018-11-27 14:50  4%                       ` Per Lundberg
  2018-11-27 15:19  6%                       ` Duy Nguyen
@ 2018-12-06 18:39 10%                       ` Duy Nguyen
  2 siblings, 0 replies; 200+ results
From: Duy Nguyen @ 2018-12-06 18:39 UTC (permalink / raw)
  To: Jacob Keller
  Cc: per.lundberg, Ævar Arnfjörð Bjarmason,
	brian m. carlson, Git Mailing List, jost, Joshua Jensen,
	Junio C Hamano, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

On Tue, Nov 27, 2018 at 1:56 PM Jacob Keller <jacob.keller@gmail.com> wrote:
> Personally, I would rather err on the side which requires the least
> interaction from users to avoid silently clobbering an ignored file.
>
> Either Duy's solution with a sort of "untracked" reflog, or the
> garbage/trashable notion.

The "untracked reflog" is partially functional now [1] if you want to
have a look. I'm not going to post the series until post-2.20, but if
you do look, I suggest the first patch that lays out the design and a
plumbing command to manage it. Basically you'll do

    git backup-log --id=worktree log <some-path>

then pick up the version you like with "git backup-log cat" and do
whatever you want with it. High level UI is not there and will be a
topic of discussion.

The precious/trashable/garbage notion can be used to suppress making backups.

[1] https://gitlab.com/pclouds/git/commits/backup-log
-- 
Duy

^ permalink raw reply	[relevance 10%]

* Re: [RFC] git clean --local
  2018-12-02 19:37  4%     ` Junio C Hamano
  2018-12-03  7:40  0%       ` Cameron Boehmer
@ 2018-12-04  2:45  7%       ` Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2018-12-04  2:45 UTC (permalink / raw)
  To: git
  Cc: 'Ævar Arnfjörð Bjarmason',
	'Cameron Boehmer', Randall S. Becker

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

> If "git clean" takes a pathspec, perhaps you can give a negative
> pathspec to exclude whatever you do not want to get cleaned,
> something like
>
> 	git clean '*.o' ':!precious.o'
>
> to say "presious.o is ignored (hence normally expendable), but I do
> not want to clean it with this invocation of 'git clean'"?

Hmph, this leads me to an interesting thought.  With today's code,
these two commands behave in meaningfully different ways when I mark
some paths that match .gitignore patterns with the precious
attribute.

	echo "*.ignored" >>.git/info/exclude
	echo "precious.* precious" >>.git/info/attributes

	: >expendable.ignored 2>precious.ignored

	git clean -n -x
	git clean -n -x ':(exclude,attr:precious)'

I am not suggesting that giving "git clean" a configuration knob
that always append pathspec elements, which would allow users to use
the mechanism to set the above magic pathspec, would be a good
approach.  If we were to follow through this line of thought, an
obvious thing to do is to always unconditonally append the above
magic pathspec internally when running "git clean", which would mean

 * Existing projects and users' repositories will see no behaviour
   change, because they are unaware of the "precious" attribute.

 * People who learn the new feature can start using the "ignored but
   precious" class, without any need for transition period.



^ permalink raw reply	[relevance 7%]

* Re: [RFC] git clean --local
  2018-12-02 19:37  4%     ` Junio C Hamano
@ 2018-12-03  7:40  0%       ` Cameron Boehmer
  2018-12-04  2:45  7%       ` Junio C Hamano
  1 sibling, 0 replies; 200+ results
From: Cameron Boehmer @ 2018-12-03  7:40 UTC (permalink / raw)
  To: gitster; +Cc: rsbecker, avarab, git

> > Would something like git clean --exclude=file-pattern work as a
> > compromise notion? Files matching the pattern would not be cleaned
> > regardless of .gitignore or their potential preciousness status
> > long-term. Multiple repetitions of the --exclude option might be
> > supportable. I could see that being somewhat useful in scripting.
>
> I think "git clean" already takes "-e", but I am not sure if it is
> meant to do what you wrote above.

It does already take --exclude=file-pattern, which is like adding
lines to .gitignore. (W/o -x/-X, that would mean DON'T clean them, but
with -x/-X, it means DO clean them.)

>
> If "git clean" takes a pathspec, perhaps you can give a negative
> pathspec to exclude whatever you do not want to get cleaned,
> something like
>
>         git clean '*.o' ':!precious.o'
>

I like this, but I'm also 100% satisfied with Junio's previous suggestion:
    git -c core.excludesFile=/dev/null clean ...

^ permalink raw reply	[relevance 0%]

* Re: [RFC] git clean --local
  2018-12-02 17:37  4%   ` Randall S. Becker
@ 2018-12-02 19:37  4%     ` Junio C Hamano
  2018-12-03  7:40  0%       ` Cameron Boehmer
  2018-12-04  2:45  7%       ` Junio C Hamano
  0 siblings, 2 replies; 200+ results
From: Junio C Hamano @ 2018-12-02 19:37 UTC (permalink / raw)
  To: Randall S. Becker
  Cc: 'Ævar Arnfjörð Bjarmason',
	'Cameron Boehmer', git

"Randall S. Becker" <rsbecker@nexbridge.com> writes:


> Would something like git clean --exclude=file-pattern work as a
> compromise notion? Files matching the pattern would not be cleaned
> regardless of .gitignore or their potential preciousness status
> long-term. Multiple repetitions of the --exclude option might be
> supportable. I could see that being somewhat useful in scripting.

I think "git clean" already takes "-e", but I am not sure if it is
meant to do what you wrote above.

If "git clean" takes a pathspec, perhaps you can give a negative
pathspec to exclude whatever you do not want to get cleaned,
something like

	git clean '*.o' ':!precious.o'

to say "presious.o is ignored (hence normally expendable), but I do
not want to clean it with this invocation of 'git clean'"?

^ permalink raw reply	[relevance 4%]

* RE: [RFC] git clean --local
  @ 2018-12-02 17:37  4%   ` Randall S. Becker
  2018-12-02 19:37  4%     ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Randall S. Becker @ 2018-12-02 17:37 UTC (permalink / raw)
  To: 'Ævar Arnfjörð Bjarmason',
	'Cameron Boehmer'
  Cc: git

On December 2, 2018 8:26, Ævar Arnfjörð Bjarmason wrote:
> 
> On Sat, Dec 01 2018, Cameron Boehmer wrote:
> 
> > 1) add a new flag
> > -l, --local
> >     Do not consult git config --global core.excludesFile in
> > determining what files git ignores. This is useful in conjunction with
> > -x/-X to preserve user files while removing build artifacts.
> 
> Or perhaps a general flag to ignore configuration would be useful for such
> cases, see https://public-
> inbox.org/git/87zhtqvm66.fsf@evledraar.gmail.com/

Would something like git clean --exclude=file-pattern work as a compromise notion? Files matching the pattern would not be cleaned regardless of .gitignore or their potential preciousness status long-term. Multiple repetitions of the --exclude option might be supportable. I could see that being somewhat useful in scripting.

Cheers,
Randall



^ permalink raw reply	[relevance 4%]

* Re: [RFC] git clean --local
  2018-12-02  0:04  4% ` Junio C Hamano
@ 2018-12-02  4:43  7%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2018-12-02  4:43 UTC (permalink / raw)
  To: Cameron Boehmer; +Cc: git

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

> Cameron Boehmer <cameron.boehmer@gmail.com> writes:
>
>> 1) add a new flag
>> -l, --local
>>     Do not consult git config --global core.excludesFile in
>> determining what files git ignores. This is useful in conjunction with
>> -x/-X to preserve user files while removing build artifacts.
> ...
> But it might be useful as an option that affects any "git" command,
> e.g. "git --local-config-only clean".  I dunno.

If you only want to say "there is no global excludes file", perhaps

    $ git -c core.excludesFile=/dev/null clean -x

may be sufficient, so for that particular use case, there is no need
to introduce a new command, I'd think.

In the longer term, however, I think we would want to introduce a
distinction among ignored files---we only support "ignored and
expendable" class, but not "ignored but precious" class.  With the
latter class introduced, it would make sense for "git clean -x/-X"
to notice that a path is ignored but precious and keep it.  If a
dir/foo is ignored, dir/bar is tracked in commit A that is currently
checked out, and there is no dir/ directory in commit B, checking
out commit B would remove dir/foo (because the last tracked file in
the directory goes away and all remaining files in the directory
would be ignored but expendable).  But if we introduced a new
"ignored but precious" class and made dir/foo a member of such a
class, then you will be prevented from checkout out B until you do
something about dir/foo that is now "precious".





^ permalink raw reply	[relevance 7%]

* Re: [RFC] git clean --local
  @ 2018-12-02  0:04  4% ` Junio C Hamano
  2018-12-02  4:43  7%   ` Junio C Hamano
    1 sibling, 1 reply; 200+ results
From: Junio C Hamano @ 2018-12-02  0:04 UTC (permalink / raw)
  To: Cameron Boehmer; +Cc: git

Cameron Boehmer <cameron.boehmer@gmail.com> writes:

> 1) add a new flag
> -l, --local
>     Do not consult git config --global core.excludesFile in
> determining what files git ignores. This is useful in conjunction with
> -x/-X to preserve user files while removing build artifacts.

This does not belong to the "clean" command (who says the need to
ignore the global configuration is limited to "clean" and why?), so
"git clean --local" is simply not acceptable.

But it might be useful as an option that affects any "git" command,
e.g. "git --local-config-only clean".  I dunno.

> 2) change the behavior of -x/-X

This won't happen without a long deprecation period.

If you haven't seen and read them, check the recent list archive for
the past few weeks, with keywords "trashable", "precious", etc.

^ permalink raw reply	[relevance 4%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-28 21:54  5%               ` Ævar Arnfjörð Bjarmason
  2018-11-29  5:04 10%                 ` Junio C Hamano
@ 2018-12-01  6:21  5%                 ` Duy Nguyen
  1 sibling, 0 replies; 200+ results
From: Duy Nguyen @ 2018-12-01  6:21 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Junio C Hamano, per.lundberg, brian m. carlson, Git Mailing List,
	jost, Joshua Jensen, git, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard

On Wed, Nov 28, 2018 at 10:54 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
> But we must have some viable way to repair warts in the tools, and
> losing user data is a *big* wart.
>
> I don't think something like the endgame you've described in
> https://public-inbox.org/git/xmqqzhtwuhpc.fsf@gitster-ct.c.googlers.com/
> is ever going to work. Novice git users (the vast majority) are not
> going to diligently update both .gitignore and some .gitattribute
> mechanism in lockstep. I'd bet most git users haven't read more than a
> few paragraphs of our entire documentation at best.
>
> So what's the way forward? I think ultimately we must move to something
> where we effectively version the entire CLI UI similar to stable API
> versions. I.e. for things like this that would break some things (or
> Duy's new "split checkout") introduce them as flags first, then bundle
> up all such flags and cut a major release "Git 3, 4, ...", and
> eventually remove old functionality.

Related to Duy's new "split chekckout", I just realized that I added
--overwrite-ignore (enabled by default) [1] years ago to allow to out
out of this behavior. We could turn --no-overwrite-ignore by default
on the new command "git switch-branch" to err on the safe side. Then
the user could switch to --overwrite-ignore once they learn more about
gitignore and gitattributes (or the coming "backup log"). I'm not sure
if I really like this, but at least it's one of the options.

[1] https://public-inbox.org/git/1322388933-6284-2-git-send-email-pclouds@gmail.com/
-- 
Duy

^ permalink raw reply	[relevance 5%]

* Re: [PATCH 3/5] pack-objects: add --sparse option
  @ 2018-11-30  2:39  4%       ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2018-11-30  2:39 UTC (permalink / raw)
  To: Derrick Stolee
  Cc: Stefan Beller, gitgitgadget, git, Jeff King,
	Ævar Arnfjörð Bjarmason, Jonathan Nieder,
	Derrick Stolee

Derrick Stolee <stolee@gmail.com> writes:

> You're right that having this hidden as an opt-in config variable
> makes it hard to discover as a typical user.
>
> I would argue that we should actually make the config setting true by
> default, and recommend that servers opt-out. Here are my reasons:
>
> 1. The vast majority of users are clients.
>
> 2. Client users are not likely to know about and tweak these settings.
>
> 3. Server users are more likely to keep an eye on the different knobs
> they can tweak.
>
> 4. Servers should use the reachability bitmaps, which don't use this
> logic anyway.
>
> While _eventually_ we should make this opt-out, we shouldn't do that
> until it has cooked a while.

I actually do not agree.  If the knob gives enough benefit, the
users will learn about it viva voce, and in a few more releases
we'll hear "enough users complain that they have to turn it on,
let's make it the default".  If that does not happen, the knob
does not deserve to be turned on in the first place.

The same applies to many shiny new toys people are discussing
recently on this list (e.g. precious vs expendable and non-overlay
checkout are the ones that immediately come to my mind).

Having said that, I won't be commenting on this shiny new toy before
the final.  I want to see more people help tying the loose ends and
give it final varnish to the upcoming release, as it seems to have
become rockier and larger release than we originally anticipated.

^ permalink raw reply	[relevance 4%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-28 21:54  5%               ` Ævar Arnfjörð Bjarmason
@ 2018-11-29  5:04 10%                 ` Junio C Hamano
  2018-12-01  6:21  5%                 ` Duy Nguyen
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2018-11-29  5:04 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Per Lundberg, brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Matthieu Moy, Clemens Buchacher, Holger Hellmuth,
	Kevin Ballard, Nguyễn Thái Ngọc Duy

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> I don't think something like the endgame you've described in
> https://public-inbox.org/git/xmqqzhtwuhpc.fsf@gitster-ct.c.googlers.com/
> is ever going to work. Novice git users (the vast majority) are not
> going to diligently update both .gitignore and some .gitattribute
> mechanism in lockstep.

That goes both ways, no?  Forcing people to add the same pattern,
e.g. *.o, to .gitignore and .gitattribute to say they are
expendable, when most of the time they are, is not something you
should expect from the normal population.

>> I would think that a proper automation needs per-path hint from the
>> user and/or the project, not just a single-size-fits-all --force
>> option, and "unlike all the *.o ignored files that are expendable,
>> this vendor-supplied-object.o is not" is one way to give such a
>> per-path hint.
>>
>>> This would give scripts which relied on our stable plumbing consistent
>>> behavior, while helping users who're using our main porcelain not to
>>> lose data. I could then add a --force option to the likes of read-tree
>>> (on by default), so you could get porcelain-like behavior with
>>> --no-force.
>>
>> At that low level, I suspect that a single size fits all "--force"
>> would work even less well.
>
> Yeah I don't think the one-size-fits-all way out of this is a single
> --force flag.

Yes, indeed.  That's why I prefer the "precious" bit.  The system
would behave the same way with or without it, but projects (not
individual endusers) can take advantage of the feature if they
wanted to.


^ permalink raw reply	[relevance 10%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-28  3:58  5%             ` Junio C Hamano
@ 2018-11-28 21:54  5%               ` Ævar Arnfjörð Bjarmason
  2018-11-29  5:04 10%                 ` Junio C Hamano
  2018-12-01  6:21  5%                 ` Duy Nguyen
  0 siblings, 2 replies; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-28 21:54 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Per Lundberg, brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Matthieu Moy, Clemens Buchacher, Holger Hellmuth,
	Kevin Ballard, Nguyễn Thái Ngọc Duy


On Wed, Nov 28 2018, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> What do you think about some patch like that which retains the plumbing
>> behavior for things like read-tree, doesn't introduce "precious" or
>> "trashable", and just makes you specify "[checkout|merge|...] --force"
>> in cases where we'd have clobbering?
>
> Whether you like it or not, don't people's automation use tons of
> invocations of "git merge", "git checkout", etc.?  You'd be breaking
> them by such a change.

I'm so sympathetic to this argument that I tried to convince you of
something like this around a year and a half ago:
https://public-inbox.org/git/CACBZZX59KXPOEjiUKtZLN6zjO_xpiWve7Xga6q-53J2LwvfZyw@mail.gmail.com/
:)

I was probing for what your current stance on this sort of thing is,
because discussions like this tend to get bogged down in the irrelevant
distraction of whether something is plumbing or porcelain, which almost
none of our users care about, and we've effectively stopped caring about
ourselves.

But we must have some viable way to repair warts in the tools, and
losing user data is a *big* wart.

I don't think something like the endgame you've described in
https://public-inbox.org/git/xmqqzhtwuhpc.fsf@gitster-ct.c.googlers.com/
is ever going to work. Novice git users (the vast majority) are not
going to diligently update both .gitignore and some .gitattribute
mechanism in lockstep. I'd bet most git users haven't read more than a
few paragraphs of our entire documentation at best.

So what's the way forward? I think ultimately we must move to something
where we effectively version the entire CLI UI similar to stable API
versions. I.e. for things like this that would break some things (or
Duy's new "split checkout") introduce them as flags first, then bundle
up all such flags and cut a major release "Git 3, 4, ...", and
eventually remove old functionality.

> Other than that, if we never had Git before and do not have to worry
> about existing users, I'd think it would be a lot closer to the ideal
> than today's system if "checkout <tree> foo.o" rejected overwriting
> "foo.o" that is not tracked in the current index but matches an ignore
> pattern, and required a "--force" option to overwrite it.
>
> A user, during a conflict resolution, may say "I want this 'git
> checkout foo/' to ignore conflicted paths in that directory, so I
> would give "--force" option to it, but now "--force" also implies
> that I am willing to clobber ignored paths, which means I cannot use
> it".
>
> I would think that a proper automation needs per-path hint from the
> user and/or the project, not just a single-size-fits-all --force
> option, and "unlike all the *.o ignored files that are expendable,
> this vendor-supplied-object.o is not" is one way to give such a
> per-path hint.
>
>> This would give scripts which relied on our stable plumbing consistent
>> behavior, while helping users who're using our main porcelain not to
>> lose data. I could then add a --force option to the likes of read-tree
>> (on by default), so you could get porcelain-like behavior with
>> --no-force.
>
> At that low level, I suspect that a single size fits all "--force"
> would work even less well.

Yeah I don't think the one-size-fits-all way out of this is a single
--force flag.

^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-28  1:21  4%                         ` brian m. carlson
@ 2018-11-28  6:54  5%                           ` Per Lundberg
  0 siblings, 0 replies; 200+ results
From: Per Lundberg @ 2018-11-28  6:54 UTC (permalink / raw)
  To: brian m. carlson
  Cc: Jacob Keller, Duy Nguyen, Ævar Arnfjörð Bjarmason,
	Git mailing list, Junio C Hamano

On 11/28/18 3:21 AM, brian m. carlson wrote:

Thanks for the elaboration, Brian - good to get things down to a 
practical, real-world level.

 > [...]
 >
> I point this out to underscore how fundamental this change is.  People
> overwhelmingly do not read the release notes, so expecting people to
> realize that a change has been made, especially when many people only
> upgrade Git because of a security issue, may result in unexpected
> consequences.

This is one of the more important things of software engineering. _Don't 
mix security fixes with breaking changes_. They are very different 
things and like you say, we can't really expect people to real release 
notes for every little incremental release we do.

That's an important part of the SemVer guarantee: a minor version 
bump/patch level increase means "bug fix" or "added functionality in a 
backwards-compatible way". So: no changing of default behavior or 
semantics, but adding a new behavior which is opt-in is perfectly fine.

> Just because we don't think of this use of Git as normal or desirable > doesn't mean people don't do it and don't expect it to keep working.

In other words, we need to be "bug-by-bug" compatible with previous 
versions. :-) What some people would consider a bug, others would 
consider a feature.

> I think any change we make here has to be opt-in, at least until Git
> 3.0.  A config knob would probably be the right way to go. 

Agree. It's less than optimal but I think it's something that we all 
could live with. Deciding to switching the default (or not) is then 
rightfully postponed to a later time, and we can revisit the pros and 
cons then. The important thing now is to get the functionality 
implemented in a good way, tested and eventually merged.
--
Per Lundberg

^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-27 15:08 10%           ` Ævar Arnfjörð Bjarmason
@ 2018-11-28  3:58  5%             ` Junio C Hamano
  2018-11-28 21:54  5%               ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2018-11-28  3:58 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Per Lundberg, brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Matthieu Moy, Clemens Buchacher, Holger Hellmuth,
	Kevin Ballard, Nguyễn Thái Ngọc Duy

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> What do you think about some patch like that which retains the plumbing
> behavior for things like read-tree, doesn't introduce "precious" or
> "trashable", and just makes you specify "[checkout|merge|...] --force"
> in cases where we'd have clobbering?

Whether you like it or not, don't people's automation use tons of
invocations of "git merge", "git checkout", etc.?  You'd be breaking
them by such a change.  Other than that, if we never had Git before
and do not have to worry about existing users, I'd think it would be
a lot closer to the ideal than today's system if "checkout <tree>
foo.o" rejected overwriting "foo.o" that is not tracked in the
current index but matches an ignore pattern, and required a
"--force" option to overwrite it.

A user, during a conflict resolution, may say "I want this 'git
checkout foo/' to ignore conflicted paths in that directory, so I
would give "--force" option to it, but now "--force" also implies
that I am willing to clobber ignored paths, which means I cannot use
it".

I would think that a proper automation needs per-path hint from the
user and/or the project, not just a single-size-fits-all --force
option, and "unlike all the *.o ignored files that are expendable,
this vendor-supplied-object.o is not" is one way to give such a
per-path hint.

> This would give scripts which relied on our stable plumbing consistent
> behavior, while helping users who're using our main porcelain not to
> lose data. I could then add a --force option to the likes of read-tree
> (on by default), so you could get porcelain-like behavior with
> --no-force.

At that low level, I suspect that a single size fits all "--force"
would work even less well.


^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-27 14:50  4%                       ` Per Lundberg
@ 2018-11-28  1:21  4%                         ` brian m. carlson
  2018-11-28  6:54  5%                           ` Per Lundberg
  0 siblings, 1 reply; 200+ results
From: brian m. carlson @ 2018-11-28  1:21 UTC (permalink / raw)
  To: Per Lundberg
  Cc: Jacob Keller, Duy Nguyen, Ævar Arnfjörð Bjarmason,
	Git mailing list, jost@tcs.ifi.lmu.de, jjensen@workspacewhiz.com,
	Junio C Hamano, Matthieu Moy, drizzd@gmx.net, hellmuth@ira.uka.de,
	kevin@sb.org

[-- Attachment #1: Type: text/plain, Size: 2982 bytes --]

On Tue, Nov 27, 2018 at 02:50:34PM +0000, Per Lundberg wrote:
> I agree strongly with this personally; if we must choose between "might
> break automation" and "might delete non-garbage files", I would say the
> former is the lesser evil of the two.
> 
> But, if I had 10 000 000 servers set up using automated scripts that
> would break because of this, I might think differently. Quite likely so,
> in fact.
> 
> What are these automation scenarios _more specifically_? Junio or Brian,
> would you care to elaborate? Is it for build servers where you want "git
> clean -dfx" to always reset the working copy to a pristine state or are
> we talking about some other scenarios?

We had long-running CI servers, since bootstrapping a new system took an
hour.  These would check out the branch to test and run some process
(essentially, a "make" and "make test").  Then, another branch would be
tested, and so on.  The old branch would likely not be merged at this
point.

The scenario I'm thinking of is when a file (say a CSS file) became
built instead of stored in the repository.  Then the file would be added
to .gitignore in the new commit, and it would be generated as part of
the make step.  It would be important to blow away that file away when
checking out a new commit, because not doing so would mean that the CI
system would simply fail to work and require manual intervention.

Moreover, a CI job might fail, due to either a flaky test or a
legitimate failures, so the job might need to be re-run multiple times.
Requiring human intervention, especially when such jobs might be running
at odd hours, would be undesirable.

Another thing we did was to use a specially named gitignore file in our
build step.  We created a new repository, copied the special gitignore
file in as .gitignore, copied in the source and build products, ran git
add and git commit, and then ran git clean -dfx to remove proprietary
source code, packaging the result.  A change to the behavior of git
clean -dfx would be devastating here.

I point this out to underscore how fundamental this change is.  People
overwhelmingly do not read the release notes, so expecting people to
realize that a change has been made, especially when many people only
upgrade Git because of a security issue, may result in unexpected
consequences.  Just because we don't think of this use of Git as normal
or desirable doesn't mean people don't do it and don't expect it to
keep working.  People do read and rely on our documentation.

I think any change we make here has to be opt-in, at least until Git
3.0.  A config knob would probably be the right way to go.  I realize
that may not provide all the benefits we want out of the box, but it
lets people turn the option on once and forget about it.  It also lets
people who don't desire this new behavior explicitly turn it off.
-- 
brian m. carlson: Houston, Texas, US
OpenPGP: https://keybase.io/bk2204

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 868 bytes --]

^ permalink raw reply	[relevance 4%]

* Re: Git pull confusing output
  2018-11-27 22:34  0%   ` Will
@ 2018-11-27 23:37  0%     ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-27 23:37 UTC (permalink / raw)
  To: Will; +Cc: git, Stefan Beller


On Tue, Nov 27 2018, Will wrote:

> On 27 Nov 2018, at 19:24, Stefan Beller wrote:
>
>> The different phases taking each one line takes up precious
>> screen real estate, so another approach would be delete the line
>> after one phase is finished, such that you'd only see the currently
>> active phase (that can be useful for debugging as in "The phase of
>> 'Writing objects' takes very long" -> slow network connection).
>
> I like this idea
>
>>>> Pushing to github.com:williamdclt/some-repo.git… done
>>>> 1ca9aaa..4320d30  master -> master
>>>
>>>
>>> I’d be more than happy to work on this (`git push` is an example
>>> amongst so many other), but want the mailing list’s opinion on it. Am
>>> I wrong in thinking that this output is not something users want, am I
>>> fighting windmills or maybe just being ignorant?
>>
>> I think this would be a useful patch, but it could get complicated
>> quickly: push uses other low level git commands to prepare the
>> packfile to be sent to the server, currently it only needs to pipe
>> through the output of the low level command (or even have the
>> low level command directly write to the terminal).
>>
>> The output of those low level commands should not be changed
>> when run on their own, I would assume.
>
> Agreed. I didn’t expect it to be so subtle, but I’ll look into it
> and see if that’s something within my reach.

It's not *quite* the same topic, but a related WIP patch that got
dropped (and it would be great if someone looking at this area could
pick it up) is
https://public-inbox.org/git/20180902085503.GA25391@sigill.intra.peff.net/

I think it's also worth looking into making the progress code able to
emit stuff like:

    Counting / Compressing / Writing objects A% (X_1/Y_2) B% (X_2/Y_2) C% (X_3/Y_3)

That would allow for splitting up some of these cases where our progress
bars are overly verbose across multiple lines without losing info by
completely erasing the line, and would also support other cases where
sometimes we do this stuff concurrently. See e.g. my recent commit-graph
progress patches for something that would benefit from this type of
thing.

It would need a patch to the progress code to make it able to juggle N
number of progress bars with some format to stitch them all together.

^ permalink raw reply	[relevance 0%]

* Re: Git pull confusing output
  2018-11-27 19:24  3% ` Stefan Beller
@ 2018-11-27 22:34  0%   ` Will
  2018-11-27 23:37  0%     ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 200+ results
From: Will @ 2018-11-27 22:34 UTC (permalink / raw)
  To: git; +Cc: Stefan Beller



On 27 Nov 2018, at 19:24, Stefan Beller wrote:

> The different phases taking each one line takes up precious
> screen real estate, so another approach would be delete the line
> after one phase is finished, such that you'd only see the currently
> active phase (that can be useful for debugging as in "The phase of
> 'Writing objects' takes very long" -> slow network connection).

I like this idea

>>> Pushing to github.com:williamdclt/some-repo.git… done
>>> 1ca9aaa..4320d30  master -> master
>>
>>
>> I’d be more than happy to work on this (`git push` is an example
>> amongst so many other), but want the mailing list’s opinion on it. Am
>> I wrong in thinking that this output is not something users want, am I
>> fighting windmills or maybe just being ignorant?
>
> I think this would be a useful patch, but it could get complicated
> quickly: push uses other low level git commands to prepare the
> packfile to be sent to the server, currently it only needs to pipe
> through the output of the low level command (or even have the
> low level command directly write to the terminal).
>
> The output of those low level commands should not be changed
> when run on their own, I would assume.

Agreed. I didn’t expect it to be so subtle, but I’ll look into it
and see if that’s something within my reach.

^ permalink raw reply	[relevance 0%]

* Re: Git pull confusing output
  @ 2018-11-27 19:24  3% ` Stefan Beller
  2018-11-27 22:34  0%   ` Will
  0 siblings, 1 reply; 200+ results
From: Stefan Beller @ 2018-11-27 19:24 UTC (permalink / raw)
  To: william.duclot; +Cc: git

On Tue, Nov 27, 2018 at 8:52 AM Will <william.duclot@gmail.com> wrote:

> And even them, do they need this info every time they push?

I agree that we should make the output a bit more user friendly,
which means we'd only want to output relevant data for the user.

The different phases taking each one line takes up precious
screen real estate, so another approach would be delete the line
after one phase is finished, such that you'd only see the currently
active phase (that can be useful for debugging as in "The phase of
'Writing objects' takes very long" -> slow network connection).

> I feel like a less intimidating output would help, while showing info
> about objects and deltas with the verbose flag:

I agree that most information in pushing is not very useful
and could be omitted. This helps in multiple ways:
* it keeps the focus on the actually important information,
   see bf1a11f0a1 (sideband: highlight keywords in remote
   sideband output, 2018-08-07)
* less space in a terminal wasted, such that you can scroll over
   it better

> > Compressing… done

After the push succeeded this information would not be useful
any more, it is only useful during the compression phase
(Does it progress quickly enough? or does it error out?)

Slightly related (but applies mostly to fetch, for which this
discussion can also be had):
When fetching, these informations are generated on the
remote side (as the server needs to create the packfile
according to your local state that you negotiated with the
server), which takes some time. Sending over this
information also keeps the connection alive. This is only
relevant in corner cases depending on the setup of the
hosting provider/repository, but it led to commits such as
https://eclipse.googlesource.com/jgit/jgit/+/a38531b21c7e2b0dc956e0ed1bfc9513f604273c
in the java implementation of Git.

> > Pushing to github.com:williamdclt/some-repo.git… done
> > 1ca9aaa..4320d30  master -> master
>
>
> I’d be more than happy to work on this (`git push` is an example
> amongst so many other), but want the mailing list’s opinion on it. Am
> I wrong in thinking that this output is not something users want, am I
> fighting windmills or maybe just being ignorant?

I think this would be a useful patch, but it could get complicated
quickly: push uses other low level git commands to prepare the
packfile to be sent to the server, currently it only needs to pipe
through the output of the low level command (or even have the
low level command directly write to the terminal).

The output of those low level commands should not be changed
when run on their own, I would assume.

So maybe the best way to dive into understanding what happens
under the hood in git-push is to run

  GIT_TRACE=1 git push ...

and see what child processes are invoked (e.g.
run_command: git pack-objects --all-progress-implied)
and then we'd need to change the output of iff the
specific progress flag is given.

Stefan

^ permalink raw reply	[relevance 3%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-27 12:55 10%                     ` Jacob Keller
  2018-11-27 14:50  4%                       ` Per Lundberg
@ 2018-11-27 15:19  6%                       ` Duy Nguyen
  2018-12-06 18:39 10%                       ` Duy Nguyen
  2 siblings, 0 replies; 200+ results
From: Duy Nguyen @ 2018-11-27 15:19 UTC (permalink / raw)
  To: Jacob Keller
  Cc: per.lundberg, Ævar Arnfjörð Bjarmason,
	brian m. carlson, Git Mailing List, jost, Joshua Jensen,
	Junio C Hamano, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

On Tue, Nov 27, 2018 at 1:56 PM Jacob Keller <jacob.keller@gmail.com> wrote:
>
> On Tue, Nov 27, 2018 at 1:45 AM Per Lundberg <per.lundberg@hibox.tv> wrote:
> >
> > On 11/26/18 5:55 PM, Duy Nguyen wrote:
> > > On Mon, Nov 26, 2018 at 4:47 PM Ævar Arnfjörð Bjarmason
> > > <avarab@gmail.com> wrote:
> > >> Some of the solutions overlap with this thing you want, but I think it's
> > >> worth keeping the distinction between the two in mind.
> > >
> > > On the other hand all use cases should be considered. It's going to be
> > > a mess to have "trashable" attribute that applies to some commands
> > > while "precious" to some others (and even worse when they overlap,
> > > imagine having to define both in .gitattributes)
> >
> > Agree - I think it would be a very bad idea to have a "mix" of both
> > trashable and precious. IMO, we should try to find which one of these
> > concepts suits most general use cases best and causes less churn for
> > existing scripts/users' existing "semantic expectations", and pick that one.
> > --
> > Per Lundberg
>
> Personally, I would rather err on the side which requires the least
> interaction from users to avoid silently clobbering an ignored file.
>
> Either Duy's solution with a sort of "untracked" reflog, or the
> garbage/trashable notion.
>
> I don't like the idea of precious because it means people have to know
> and remember to opt in, and it's quite possible they will not do so
> until after they've lost real data.
>
> I'd only have trashable apply in the case where it was implicit. i.e.
> git clean -fdx would still delete them, as this is an explicit
> operation that (hopefully?) users know will delete data.

Yes I know it will delete ignored files. But I don't want it to delete
some files. There is no way I can tell Git to do that.

It's the same with merge/checkout's overwriting problem. Once the
initial surprise is over, I want control over what files I want Git to
just delete and not annoy me, what Git should not delete.
-- 
Duy

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26 12:49 12%         ` Junio C Hamano
@ 2018-11-27 15:08 10%           ` Ævar Arnfjörð Bjarmason
  2018-11-28  3:58  5%             ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-27 15:08 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Per Lundberg, brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Matthieu Moy, Clemens Buchacher, Holger Hellmuth,
	Kevin Ballard, Nguyễn Thái Ngọc Duy


On Mon, Nov 26 2018, Junio C Hamano wrote:

> Per Lundberg <per.lundberg@hibox.tv> writes:
>
>> How about something like this:
>> ...
>> Would this be a reasonable compromise for everybody?
>
> I do not think you'd need to introduce such a deliberately breaking
> change at all.  Just introduce a new "precious" class, perhaps mark
> them with the atttribute mechanism, and that would be the endgame.
> Early adopters would start marking ignored but not expendable paths
> with the "precious" attribute and they won't be clobbered.  As the
> mechanism becomes widely known and mature, more and more people use
> it.  And even after that happens, early adopters do not have to change
> any attribute setting, and late adopters would have plenty of examples
> to imitate.  Those who do not need any "precious" class do not have
> to do anything and you won't break any existing automation that way.

The patch I submitted in <87zhuf3gs0.fsf@evledraar.gmail.com>[1] changed
the behavior for read-tree & checkout & merge etc.

It was an RFC more in the spirit of showing what in our current tests
had to change to spur some discussion.

But I'm very sympathetic to this line of argument. I.e. in my patch I'm
changing the semantics of read-tree, which is plumbing.

What do you think about some patch like that which retains the plumbing
behavior for things like read-tree, doesn't introduce "precious" or
"trashable", and just makes you specify "[checkout|merge|...] --force"
in cases where we'd have clobbering?

This would give scripts which relied on our stable plumbing consistent
behavior, while helping users who're using our main porcelain not to
lose data. I could then add a --force option to the likes of read-tree
(on by default), so you could get porcelain-like behavior with
--no-force.

1. https://public-inbox.org/git/87zhuf3gs0.fsf@evledraar.gmail.com/

^ permalink raw reply	[relevance 10%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-27 12:55 10%                     ` Jacob Keller
@ 2018-11-27 14:50  4%                       ` Per Lundberg
  2018-11-28  1:21  4%                         ` brian m. carlson
  2018-11-27 15:19  6%                       ` Duy Nguyen
  2018-12-06 18:39 10%                       ` Duy Nguyen
  2 siblings, 1 reply; 200+ results
From: Per Lundberg @ 2018-11-27 14:50 UTC (permalink / raw)
  To: Jacob Keller
  Cc: Duy Nguyen, Ævar Arnfjörð Bjarmason,
	brian m. carlson, Git mailing list, jost@tcs.ifi.lmu.de,
	jjensen@workspacewhiz.com, Junio C Hamano, Matthieu Moy,
	drizzd@gmx.net, hellmuth@ira.uka.de, kevin@sb.org

On 11/27/18 2:55 PM, Jacob Keller wrote:

> Personally, I would rather err on the side which requires the least
> interaction from users to avoid silently clobbering an ignored file.
> 
 > [...]
> 
> I don't like the idea of precious because it means people have to know
> and remember to opt in, and it's quite possible they will not do so
> until after they've lost real data.

I agree strongly with this personally; if we must choose between "might 
break automation" and "might delete non-garbage files", I would say the 
former is the lesser evil of the two.

But, if I had 10 000 000 servers set up using automated scripts that 
would break because of this, I might think differently. Quite likely so, 
in fact.

What are these automation scenarios _more specifically_? Junio or Brian, 
would you care to elaborate? Is it for build servers where you want "git 
clean -dfx" to always reset the working copy to a pristine state or are 
we talking about some other scenarios?

> I'd only have trashable apply in the case where it was implicit. i.e.
> git clean -fdx would still delete them, as this is an explicit
> operation that (hopefully?) users know will delete data.

This is one of the tougher calls, unfortunately.

If I was a user (which I am), and I was typing "git clean -dfx", what 
would I expect?

The help text (currently) states "-x   remove ignored files, too".

Would it be safe to assume that people would understand that "ignored 
_does not_ mean trashable when doing "git checkout some-ref" BUT it 
_does_ mean trashable in the "git clean -dfx" context"? I'm not so 
certain. It would be one of those perceived inconsistencies that would 
make people scream in anger because they _presumed_ that with the new 
"trashable" concept, "git clean -dfx" would no longer hit them in the leg.

And the other way around: if we change "git clean -dfx" to _not_ treat 
"ignored == trashable", it is likely to "hose automation" as it has been 
previously stated. People who might be using this syntax and _want_ it 
to remove ignored files would be upset, and rightfully so.

So in my POV, it's a tough decision between two, less-than-optimal 
alternatives.

But I would perhaps be able to live with the current semantics for "git 
clean -dfx" _as long as we update the help text_ so that "-x" indicates 
more clearly that non-trashable files can be deleted. It doesn't make 
things _worse_ than they currently are and if this is what it takes to 
get the trashable concept implemented and accepted by the community, 
it's a compromise I'd be willing to make.
--
Per Lundberg


^ permalink raw reply	[relevance 4%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-27  9:43 11%                   ` Per Lundberg
@ 2018-11-27 12:55 10%                     ` Jacob Keller
  2018-11-27 14:50  4%                       ` Per Lundberg
                                         ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Jacob Keller @ 2018-11-27 12:55 UTC (permalink / raw)
  To: per.lundberg
  Cc: Duy Nguyen, Ævar Arnfjörð Bjarmason,
	brian m. carlson, Git mailing list, jost, jjensen, Junio C Hamano,
	Matthieu Moy, drizzd, hellmuth, kevin

On Tue, Nov 27, 2018 at 1:45 AM Per Lundberg <per.lundberg@hibox.tv> wrote:
>
> On 11/26/18 5:55 PM, Duy Nguyen wrote:
> > On Mon, Nov 26, 2018 at 4:47 PM Ævar Arnfjörð Bjarmason
> > <avarab@gmail.com> wrote:
> >> Some of the solutions overlap with this thing you want, but I think it's
> >> worth keeping the distinction between the two in mind.
> >
> > On the other hand all use cases should be considered. It's going to be
> > a mess to have "trashable" attribute that applies to some commands
> > while "precious" to some others (and even worse when they overlap,
> > imagine having to define both in .gitattributes)
>
> Agree - I think it would be a very bad idea to have a "mix" of both
> trashable and precious. IMO, we should try to find which one of these
> concepts suits most general use cases best and causes less churn for
> existing scripts/users' existing "semantic expectations", and pick that one.
> --
> Per Lundberg

Personally, I would rather err on the side which requires the least
interaction from users to avoid silently clobbering an ignored file.

Either Duy's solution with a sort of "untracked" reflog, or the
garbage/trashable notion.

I don't like the idea of precious because it means people have to know
and remember to opt in, and it's quite possible they will not do so
until after they've lost real data.

I'd only have trashable apply in the case where it was implicit. i.e.
git clean -fdx would still delete them, as this is an explicit
operation that (hopefully?) users know will delete data.

Thanks,
Jake

^ permalink raw reply	[relevance 10%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26 15:55 11%                 ` Duy Nguyen
@ 2018-11-27  9:43 11%                   ` Per Lundberg
  2018-11-27 12:55 10%                     ` Jacob Keller
  0 siblings, 1 reply; 200+ results
From: Per Lundberg @ 2018-11-27  9:43 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Ævar Arnfjörð Bjarmason, brian m. carlson,
	Git Mailing List, jost@tcs.ifi.lmu.de, Joshua Jensen,
	Junio C Hamano, git@matthieu-moy.fr, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard

On 11/26/18 5:55 PM, Duy Nguyen wrote:
> On Mon, Nov 26, 2018 at 4:47 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>> Some of the solutions overlap with this thing you want, but I think it's
>> worth keeping the distinction between the two in mind.
> 
> On the other hand all use cases should be considered. It's going to be
> a mess to have "trashable" attribute that applies to some commands
> while "precious" to some others (and even worse when they overlap,
> imagine having to define both in .gitattributes)

Agree - I think it would be a very bad idea to have a "mix" of both 
trashable and precious. IMO, we should try to find which one of these 
concepts suits most general use cases best and causes less churn for 
existing scripts/users' existing "semantic expectations", and pick that one.
--
Per Lundberg

^ permalink raw reply	[relevance 11%]

* [PATCH v2 2/2] unpack-trees: support core.allIgnoredFilesArePreciousWhenMerging
  2018-11-26 19:38  6% ` [PATCH v2 0/2] Precios files round two Nguyễn Thái Ngọc Duy
  2018-11-26 19:38 19%   ` [PATCH v2 1/2] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
@ 2018-11-26 19:38 17%   ` Nguyễn Thái Ngọc Duy
  1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-11-26 19:38 UTC (permalink / raw)
  To: pclouds
  Cc: git, Junio C Hamano, bert.wesarg, Ævar Arnfjörð,
	drizzd, git, hellmuth, jjensen, jost, kevin, per.lundberg,
	sandals, eckhard.s.maass

Ignored files can be marked precious to prevent being overwritten
during a merge (or even a branch switch). If you really want to make
sure no ignored files are overwritten, this config variable is for
you.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config/core.txt |  6 ++++++
 Documentation/gitignore.txt   |  5 +++--
 unpack-trees.c                | 21 ++++++++++++++++++++-
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index d0e6635fe0..bff5834c13 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -1,3 +1,9 @@
+core.allIgnoredFilesArePreciousWhenMerging::
+	During a merge operation, if "precious" attribute is unset,
+	consider it set. You can explicitly remove "precious"
+	attribute if needed. See linkgit:gitattributes[5] for more
+	information.
+
 core.fileMode::
 	Tells Git if the executable bit of files in the working tree
 	is to be honored.
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 0e9614289e..2832df7178 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -142,8 +142,9 @@ To stop tracking a file that is currently tracked, use
 'git rm --cached'.
 
 Ignored files are generally considered discardable. See `precious`
-attribute in linkgit:gitattributes[5] to change the behavior regarding
-ignored files.
+attribute in linkgit:gitattributes[5] and
+`core.allIgnoredFilesArePreciousWhenMerging` in linkgit:git-config[1]
+to change the behavior regarding ignored files.
 
 EXAMPLES
 --------
diff --git a/unpack-trees.c b/unpack-trees.c
index 9a5aadc084..df3b163e2e 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1877,6 +1877,25 @@ static int icase_exists(struct unpack_trees_options *o, const char *name, int le
 	return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 }
 
+static int is_precious_ignored_file(struct index_state *istate, const char *path)
+{
+	static struct attr_check *check;
+	int all_precious;
+
+	if (!check)
+		check = attr_check_initl("precious", NULL);
+	if (!check)
+		return 0;
+
+	git_check_attr(istate, path, check);
+	if (ATTR_UNSET(check->items[0].value) &&
+	    !git_config_get_bool("core.allignoredfilesarepreciouswhenmerging",
+				 &all_precious) &&
+	    all_precious)
+		return 1;
+	return ATTR_TRUE(check->items[0].value);
+}
+
 static int check_ok_to_remove(const char *name, int len, int dtype,
 			      const struct cache_entry *ce, struct stat *st,
 			      enum unpack_trees_error_types error_type,
@@ -1895,7 +1914,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
 		return 0;
 
 	if (o->dir &&
-	    !is_precious_file(o->src_index, name) &&
+	    !is_precious_ignored_file(o->src_index, name) &&
 	    is_excluded(o->dir, o->src_index, name, &dtype))
 		/*
 		 * ce->name is explicitly excluded, so it is Ok to
-- 
2.19.1.1327.g328c130451.dirty


^ permalink raw reply related	[relevance 17%]

* [PATCH v2 1/2] Introduce "precious" file concept
  2018-11-26 19:38  6% ` [PATCH v2 0/2] Precios files round two Nguyễn Thái Ngọc Duy
@ 2018-11-26 19:38 19%   ` Nguyễn Thái Ngọc Duy
  2018-11-26 19:38 17%   ` [PATCH v2 2/2] unpack-trees: support core.allIgnoredFilesArePreciousWhenMerging Nguyễn Thái Ngọc Duy
  1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-11-26 19:38 UTC (permalink / raw)
  To: pclouds
  Cc: git, Junio C Hamano, bert.wesarg, Ævar Arnfjörð,
	drizzd, git, hellmuth, jjensen, jost, kevin, per.lundberg,
	sandals, eckhard.s.maass

A new attribute "precious" is added to indicate that certain files
have valuable content and should not be easily discarded even if they
are ignored or untracked.

So far there are two parts of Git that are made aware of precious
files: "git clean" will leave precious files alone and unpack-trees.c
(i.e. merges and branch switches) will not overwrite
ignored-but-precious files.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-clean.txt     |  3 ++-
 Documentation/gitattributes.txt | 13 +++++++++++++
 Documentation/gitignore.txt     |  4 ++++
 attr.c                          | 12 ++++++++++++
 attr.h                          |  2 ++
 builtin/clean.c                 | 20 +++++++++++++++++---
 t/t1004-read-tree-m-u-wf.sh     |  6 ++++++
 t/t7300-clean.sh                | 29 +++++++++++++++++++++++++++++
 unpack-trees.c                  |  1 +
 9 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 03056dad0d..a9beadfb12 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -21,7 +21,8 @@ option is specified, ignored files are also removed. This can, for
 example, be useful to remove all build products.
 
 If any optional `<path>...` arguments are given, only those paths
-are affected.
+are affected. Ignored or untracked files with `precious` attributes
+are not removed.
 
 OPTIONS
 -------
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index b8392fc330..b027abea4a 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -1188,6 +1188,19 @@ If this attribute is not set or has an invalid value, the value of the
 (See linkgit:git-config[1]).
 
 
+Precious files
+~~~~~~~~~~~~~~
+
+`precious`
+^^^^^^^^^^
+
+This attribute is set on files to indicate that their content is
+valuable. Many commands will behave slightly different on precious
+files. linkgit:git-clean[1] will leave precious files alone. Merging
+and branch switching will not silently overwrite ignored files that
+are marked "precious".
+
+
 USING MACRO ATTRIBUTES
 ----------------------
 
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 1c94f08ff4..0e9614289e 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -141,6 +141,10 @@ not tracked by Git remain untracked.
 To stop tracking a file that is currently tracked, use
 'git rm --cached'.
 
+Ignored files are generally considered discardable. See `precious`
+attribute in linkgit:gitattributes[5] to change the behavior regarding
+ignored files.
+
 EXAMPLES
 --------
 
diff --git a/attr.c b/attr.c
index eaece6658d..b07d8cd835 100644
--- a/attr.c
+++ b/attr.c
@@ -1172,3 +1172,15 @@ void attr_start(void)
 	pthread_mutex_init(&g_attr_hashmap.mutex, NULL);
 	pthread_mutex_init(&check_vector.mutex, NULL);
 }
+
+int is_precious_file(struct index_state *istate, const char *path)
+{
+	static struct attr_check *check;
+	if (!check)
+		check = attr_check_initl("precious", NULL);
+	if (!check)
+		return 0;
+
+	git_check_attr(istate, path, check);
+	return ATTR_TRUE(check->items[0].value);
+}
diff --git a/attr.h b/attr.h
index b0378bfe5f..b9a9751a66 100644
--- a/attr.h
+++ b/attr.h
@@ -82,4 +82,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction);
 
 void attr_start(void);
 
+int is_precious_file(struct index_state *istate, const char *path);
+
 #endif /* ATTR_H */
diff --git a/builtin/clean.c b/builtin/clean.c
index bbcdeb2d9e..42cd040849 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -17,6 +17,7 @@
 #include "color.h"
 #include "pathspec.h"
 #include "help.h"
+#include "attr.h"
 
 static int force = -1; /* unset */
 static int interactive;
@@ -30,6 +31,8 @@ static const char *const builtin_clean_usage[] = {
 
 static const char *msg_remove = N_("Removing %s\n");
 static const char *msg_would_remove = N_("Would remove %s\n");
+static const char *msg_skip_precious = N_("Skipping precious file %s\n");
+static const char *msg_would_skip_precious = N_("Would skip precious file %s\n");
 static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 static const char *msg_warn_remove_failed = N_("failed to remove %s");
@@ -153,6 +156,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 	struct dirent *e;
 	int res = 0, ret = 0, gone = 1, original_len = path->len, len;
 	struct string_list dels = STRING_LIST_INIT_DUP;
+	const char *rel_path;
 
 	*dir_gone = 1;
 
@@ -192,9 +196,16 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 
 		strbuf_setlen(path, len);
 		strbuf_addstr(path, e->d_name);
-		if (lstat(path->buf, &st))
+		if (lstat(path->buf, &st)) {
 			; /* fall thru */
-		else if (S_ISDIR(st.st_mode)) {
+		} else if ((!prefix && is_precious_file(&the_index, path->buf)) ||
+			   (prefix && skip_prefix(path->buf, prefix, &rel_path) &&
+			    is_precious_file(&the_index, rel_path))) {
+			quote_path_relative(path->buf, prefix, &quoted);
+			printf(dry_run ? _(msg_would_skip_precious) : _(msg_skip_precious), quoted.buf);
+			*dir_gone = 0;
+			continue;
+		} else if (S_ISDIR(st.st_mode)) {
 			if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
 				ret = 1;
 			if (gone) {
@@ -1018,7 +1029,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 		if (lstat(abs_path.buf, &st))
 			continue;
 
-		if (S_ISDIR(st.st_mode)) {
+		if (is_precious_file(&the_index, item->string)) {
+			qname = quote_path_relative(item->string, NULL, &buf);
+			printf(dry_run ? _(msg_would_skip_precious) : _(msg_skip_precious), qname);
+		} else if (S_ISDIR(st.st_mode)) {
 			if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone))
 				errors++;
 			if (gone && !quiet) {
diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh
index c13578a635..17dc626f62 100755
--- a/t/t1004-read-tree-m-u-wf.sh
+++ b/t/t1004-read-tree-m-u-wf.sh
@@ -63,6 +63,12 @@ test_expect_success 'two-way with incorrect --exclude-per-directory (2)' '
 	fi
 '
 
+test_expect_success 'two-way not clobbering a precious ignored file' '
+	test_when_finished rm -f .git/info/attributes &&
+	echo "file2 precious" >.git/info/attributes &&
+	read_tree_u_must_fail -m -u --exclude-per-directory=.gitignore master side
+'
+
 test_expect_success 'two-way clobbering a ignored file' '
 
 	read_tree_u_must_succeed -m -u --exclude-per-directory=.gitignore master side
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index 7b36954d63..a478a08a27 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -669,4 +669,33 @@ test_expect_success 'git clean -d skips untracked dirs containing ignored files'
 	test_path_is_missing foo/b/bb
 '
 
+test_expect_success 'git clean -xd leaves precious files alone' '
+	git init precious &&
+	(
+		cd precious &&
+		test_commit one &&
+		cat >.gitignore <<-\EOF &&
+		*.o
+		*.mak
+		EOF
+		cat >.gitattributes <<-\EOF &&
+		*.mak precious
+		.gitattributes precious
+		*.precious precious
+		EOF
+		mkdir sub &&
+		touch one.o sub/two.o one.mak sub/two.mak &&
+		touch one.untracked two.precious sub/also.precious &&
+		git clean -fdx &&
+		test_path_is_missing one.o &&
+		test_path_is_missing sub/two.o &&
+		test_path_is_missing one.untracked &&
+		test_path_is_file .gitattributes &&
+		test_path_is_file one.mak &&
+		test_path_is_file sub/two.mak &&
+		test_path_is_file two.precious &&
+		test_path_is_file sub/also.precious
+	)
+'
+
 test_done
diff --git a/unpack-trees.c b/unpack-trees.c
index 7570df481b..9a5aadc084 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1895,6 +1895,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
 		return 0;
 
 	if (o->dir &&
+	    !is_precious_file(o->src_index, name) &&
 	    is_excluded(o->dir, o->src_index, name, &dtype))
 		/*
 		 * ce->name is explicitly excluded, so it is Ok to
-- 
2.19.1.1327.g328c130451.dirty


^ permalink raw reply related	[relevance 19%]

* [PATCH v2 0/2] Precios files round two
  2018-11-11  9:52 20% [RFC PATCH] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2018-11-11 12:59 12% ` Junio C Hamano
@ 2018-11-26 19:38  6% ` Nguyễn Thái Ngọc Duy
  2018-11-26 19:38 19%   ` [PATCH v2 1/2] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
  2018-11-26 19:38 17%   ` [PATCH v2 2/2] unpack-trees: support core.allIgnoredFilesArePreciousWhenMerging Nguyễn Thái Ngọc Duy
  3 siblings, 2 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-11-26 19:38 UTC (permalink / raw)
  To: pclouds
  Cc: git, Junio C Hamano, bert.wesarg, Ævar Arnfjörð,
	drizzd, git, hellmuth, jjensen, jost, kevin, per.lundberg,
	sandals, eckhard.s.maass

Let's see if I can make everybody almost happy with this.

Patch 1 is not that much different from round one except now with
tests. It is still about "precious" attributes that prevent content
loss with "git clean", "git checkout <ref>" or "git merge".

Patch 2 goes Ævar and Per are pursuing. It adds an opt-in config that
turns all ignored files precious, but only for unpack-trees
operations.

Nguyễn Thái Ngọc Duy (2):
  Introduce "precious" file concept
  unpack-trees: support core.allIgnoredFilesArePreciousWhenMerging

 Documentation/config/core.txt   |  6 ++++++
 Documentation/git-clean.txt     |  3 ++-
 Documentation/gitattributes.txt | 13 +++++++++++++
 Documentation/gitignore.txt     |  5 +++++
 attr.c                          | 12 ++++++++++++
 attr.h                          |  2 ++
 builtin/clean.c                 | 20 +++++++++++++++++---
 t/t1004-read-tree-m-u-wf.sh     |  6 ++++++
 t/t7300-clean.sh                | 29 +++++++++++++++++++++++++++++
 unpack-trees.c                  | 20 ++++++++++++++++++++
 10 files changed, 112 insertions(+), 4 deletions(-)

-- 
2.19.1.1327.g328c130451.dirty


^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12 23:22  5%     ` brian m. carlson
  2018-11-26  9:30  5%       ` Per Lundberg
@ 2018-11-26 16:02  6%       ` Eckhard Maaß
  1 sibling, 0 replies; 200+ results
From: Eckhard Maaß @ 2018-11-26 16:02 UTC (permalink / raw)
  To: brian m. carlson
  Cc: Ævar Arnfjörð Bjarmason,
	Nguyễn Thái Ngọc Duy, git, Steffen Jost,
	Joshua Jensen, Per Lundberg, Junio C Hamano, Matthieu Moy,
	Clemens Buchacher, Holger Hellmuth, Kevin Ballard

On Mon, Nov 12, 2018 at 11:22:09PM +0000, brian m. carlson wrote:
> This is going to totally hose automation.  My last job had files which
> might move from tracked to untracked (a file that had become generated),
> and long-running CI and build systems would need to be able to check out
> one status and switch to the other.  Your proposed change will prevent
> those systems from working, whereas they previously did.

Wouldn't those systems not use -f right now? And shouldn't Git have the
same semantic for -f to clobber everything in the proposed use case?
Like it does right now for untracked files which are not ignored. So to
be save going back and forth I would expect those systems to use -f
anyway. Have I missed something here?

Regards,
Eckhard

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26 15:47  6%               ` Ævar Arnfjörð Bjarmason
@ 2018-11-26 15:55 11%                 ` Duy Nguyen
  2018-11-27  9:43 11%                   ` Per Lundberg
  0 siblings, 1 reply; 200+ results
From: Duy Nguyen @ 2018-11-26 15:55 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: per.lundberg, brian m. carlson, Git Mailing List, jost,
	Joshua Jensen, Junio C Hamano, git, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard

On Mon, Nov 26, 2018 at 4:47 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
> >> >> How about something like this:
> >> >>
> >> >> 1. Introduce a concept with "garbage" files, which git is "permitted to
> >> >> delete" without prompting.
> >> >>
> >> >> 2. Retain the current default, i.e. "ignored files are garbage" for now,
> >> >> making the new behavior _opt in_ to avoid breaking automated
> >> >> systems/existing scripts for anyone. Put the setting for this behind a
> >> >> new core.* config flag.
> >> >>
> >> >> 3. In the plan for version 3.0 (a new major version where some breakage
> >> >> can be tolerable, according to Semantic Versioning), change the default
> >> >> so that "only explicit garbage is garbage". Include very clear notices
> >> >> of this in the release notes. The config flag is retained, but its
> >> >> default changes from true->false or vice versa. People who dislike the
> >> >> new behavior can easily change back to the 2.x semantics.
> >> >
> >> > How does this garbage thing interact with "git clean -x"? My
> >> > interpretation of this flag/attribute is that at version 3.0 by
> >> > default all ignored files are _not_ garbage, so "git clean -x" should
> >> > not remove any of them. Which is weird because most of ignored files
> >> > are like *.o that should be removed.
> >> >
> >> > I also need to mark "precious" on untracked or even tracked files (*).
> >> > Not sure how this "garbage" attribute interacts with that.
> >> >
> >> > (*) I was hoping I could get the idea [1] implemented in somewhat good
> >> > shape before presenting here. But I'm a bit slow on that front. So
> >> > yeah this "precious" on untracked/tracked thingy may be even
> >> > irrelevant if the patch series will be rejected.
> >>
> >> I think a garbage (or trashable) flag, if implemented, wouldn't need any
> >> special case in git-clean, i.e. -x would remove all untracked files,
> >> whether ignored or garbage/trashable. That's what my patch to implement
> >> it does:
> >> https://public-inbox.org/git/87zhuf3gs0.fsf@evledraar.gmail.com/
> >>
> >> I think that makes sense. Users running "git clean" have "--dry-run" and
> >> unlike "checkout a branch" or "merge this commit" where we'll now shred
> >> data implicitly it's obvious that git-clean is going to shred your data.
> >
> > Then that't not what I want. If I'm going to mark to keep "config.mak"
> > around, I'm not going to carefully move it away before doing "git
> > clean -fdx" then move it back. No "git clean --dry-run" telling me to
> > make a backup of config.mak is no good.
>
> Understood. I mean this in the context of solving the problem users have
> with running otherwise non-data-destroying commands like "checkout" and
> "merge" and getting their data destroyed, which is overwhelmingly why
> this topic gets resurrected.
>
> Some of the solutions overlap with this thing you want, but I think it's
> worth keeping the distinction between the two in mind.

On the other hand all use cases should be considered. It's going to be
a mess to have "trashable" attribute that applies to some commands
while "precious" to some others (and even worse when they overlap,
imagine having to define both in .gitattributes)

> I.e. I can
> imagine us finding some acceptable solution to the data shredding
> problem that doesn't implement this mode for "git-clean", or the other
> way around.
-- 
Duy

^ permalink raw reply	[relevance 11%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26 15:40  6%             ` Duy Nguyen
@ 2018-11-26 15:47  6%               ` Ævar Arnfjörð Bjarmason
  2018-11-26 15:55 11%                 ` Duy Nguyen
  0 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-26 15:47 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: per.lundberg, brian m. carlson, Git Mailing List, jost,
	Joshua Jensen, Junio C Hamano, git, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard


On Mon, Nov 26 2018, Duy Nguyen wrote:

> On Mon, Nov 26, 2018 at 4:34 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>>
>>
>> On Mon, Nov 26 2018, Duy Nguyen wrote:
>>
>> > On Mon, Nov 26, 2018 at 10:30 AM Per Lundberg <per.lundberg@hibox.tv> wrote:
>> >>
>> >> On 11/13/18 1:22 AM, brian m. carlson wrote:
>> >> > This is going to totally hose automation.  My last job had files which
>> >> > might move from tracked to untracked (a file that had become generated),
>> >> > and long-running CI and build systems would need to be able to check out
>> >> > one status and switch to the other.  Your proposed change will prevent
>> >> > those systems from working, whereas they previously did.
>> >> >
>> >> > I agree that your proposal would have been a better design originally,
>> >> > but breaking the way automated systems currently work is probably going
>> >> > to be a dealbreaker.
>> >>
>> >> How about something like this:
>> >>
>> >> 1. Introduce a concept with "garbage" files, which git is "permitted to
>> >> delete" without prompting.
>> >>
>> >> 2. Retain the current default, i.e. "ignored files are garbage" for now,
>> >> making the new behavior _opt in_ to avoid breaking automated
>> >> systems/existing scripts for anyone. Put the setting for this behind a
>> >> new core.* config flag.
>> >>
>> >> 3. In the plan for version 3.0 (a new major version where some breakage
>> >> can be tolerable, according to Semantic Versioning), change the default
>> >> so that "only explicit garbage is garbage". Include very clear notices
>> >> of this in the release notes. The config flag is retained, but its
>> >> default changes from true->false or vice versa. People who dislike the
>> >> new behavior can easily change back to the 2.x semantics.
>> >
>> > How does this garbage thing interact with "git clean -x"? My
>> > interpretation of this flag/attribute is that at version 3.0 by
>> > default all ignored files are _not_ garbage, so "git clean -x" should
>> > not remove any of them. Which is weird because most of ignored files
>> > are like *.o that should be removed.
>> >
>> > I also need to mark "precious" on untracked or even tracked files (*).
>> > Not sure how this "garbage" attribute interacts with that.
>> >
>> > (*) I was hoping I could get the idea [1] implemented in somewhat good
>> > shape before presenting here. But I'm a bit slow on that front. So
>> > yeah this "precious" on untracked/tracked thingy may be even
>> > irrelevant if the patch series will be rejected.
>>
>> I think a garbage (or trashable) flag, if implemented, wouldn't need any
>> special case in git-clean, i.e. -x would remove all untracked files,
>> whether ignored or garbage/trashable. That's what my patch to implement
>> it does:
>> https://public-inbox.org/git/87zhuf3gs0.fsf@evledraar.gmail.com/
>>
>> I think that makes sense. Users running "git clean" have "--dry-run" and
>> unlike "checkout a branch" or "merge this commit" where we'll now shred
>> data implicitly it's obvious that git-clean is going to shred your data.
>
> Then that't not what I want. If I'm going to mark to keep "config.mak"
> around, I'm not going to carefully move it away before doing "git
> clean -fdx" then move it back. No "git clean --dry-run" telling me to
> make a backup of config.mak is no good.

Understood. I mean this in the context of solving the problem users have
with running otherwise non-data-destroying commands like "checkout" and
"merge" and getting their data destroyed, which is overwhelmingly why
this topic gets resurrected.

Some of the solutions overlap with this thing you want, but I think it's
worth keeping the distinction between the two in mind. I.e. I can
imagine us finding some acceptable solution to the data shredding
problem that doesn't implement this mode for "git-clean", or the other
way around.

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26 15:34  6%           ` Ævar Arnfjörð Bjarmason
@ 2018-11-26 15:40  6%             ` Duy Nguyen
  2018-11-26 15:47  6%               ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 200+ results
From: Duy Nguyen @ 2018-11-26 15:40 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: per.lundberg, brian m. carlson, Git Mailing List, jost,
	Joshua Jensen, Junio C Hamano, git, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard

On Mon, Nov 26, 2018 at 4:34 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
>
> On Mon, Nov 26 2018, Duy Nguyen wrote:
>
> > On Mon, Nov 26, 2018 at 10:30 AM Per Lundberg <per.lundberg@hibox.tv> wrote:
> >>
> >> On 11/13/18 1:22 AM, brian m. carlson wrote:
> >> > This is going to totally hose automation.  My last job had files which
> >> > might move from tracked to untracked (a file that had become generated),
> >> > and long-running CI and build systems would need to be able to check out
> >> > one status and switch to the other.  Your proposed change will prevent
> >> > those systems from working, whereas they previously did.
> >> >
> >> > I agree that your proposal would have been a better design originally,
> >> > but breaking the way automated systems currently work is probably going
> >> > to be a dealbreaker.
> >>
> >> How about something like this:
> >>
> >> 1. Introduce a concept with "garbage" files, which git is "permitted to
> >> delete" without prompting.
> >>
> >> 2. Retain the current default, i.e. "ignored files are garbage" for now,
> >> making the new behavior _opt in_ to avoid breaking automated
> >> systems/existing scripts for anyone. Put the setting for this behind a
> >> new core.* config flag.
> >>
> >> 3. In the plan for version 3.0 (a new major version where some breakage
> >> can be tolerable, according to Semantic Versioning), change the default
> >> so that "only explicit garbage is garbage". Include very clear notices
> >> of this in the release notes. The config flag is retained, but its
> >> default changes from true->false or vice versa. People who dislike the
> >> new behavior can easily change back to the 2.x semantics.
> >
> > How does this garbage thing interact with "git clean -x"? My
> > interpretation of this flag/attribute is that at version 3.0 by
> > default all ignored files are _not_ garbage, so "git clean -x" should
> > not remove any of them. Which is weird because most of ignored files
> > are like *.o that should be removed.
> >
> > I also need to mark "precious" on untracked or even tracked files (*).
> > Not sure how this "garbage" attribute interacts with that.
> >
> > (*) I was hoping I could get the idea [1] implemented in somewhat good
> > shape before presenting here. But I'm a bit slow on that front. So
> > yeah this "precious" on untracked/tracked thingy may be even
> > irrelevant if the patch series will be rejected.
>
> I think a garbage (or trashable) flag, if implemented, wouldn't need any
> special case in git-clean, i.e. -x would remove all untracked files,
> whether ignored or garbage/trashable. That's what my patch to implement
> it does:
> https://public-inbox.org/git/87zhuf3gs0.fsf@evledraar.gmail.com/
>
> I think that makes sense. Users running "git clean" have "--dry-run" and
> unlike "checkout a branch" or "merge this commit" where we'll now shred
> data implicitly it's obvious that git-clean is going to shred your data.

Then that't not what I want. If I'm going to mark to keep "config.mak"
around, I'm not going to carefully move it away before doing "git
clean -fdx" then move it back. No "git clean --dry-run" telling me to
make a backup of config.mak is no good.
-- 
Duy

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26 15:26 11%         ` Duy Nguyen
@ 2018-11-26 15:34  6%           ` Ævar Arnfjörð Bjarmason
  2018-11-26 15:40  6%             ` Duy Nguyen
  0 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-26 15:34 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: per.lundberg, brian m. carlson, Git Mailing List, jost,
	Joshua Jensen, Junio C Hamano, git, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard


On Mon, Nov 26 2018, Duy Nguyen wrote:

> On Mon, Nov 26, 2018 at 10:30 AM Per Lundberg <per.lundberg@hibox.tv> wrote:
>>
>> On 11/13/18 1:22 AM, brian m. carlson wrote:
>> > This is going to totally hose automation.  My last job had files which
>> > might move from tracked to untracked (a file that had become generated),
>> > and long-running CI and build systems would need to be able to check out
>> > one status and switch to the other.  Your proposed change will prevent
>> > those systems from working, whereas they previously did.
>> >
>> > I agree that your proposal would have been a better design originally,
>> > but breaking the way automated systems currently work is probably going
>> > to be a dealbreaker.
>>
>> How about something like this:
>>
>> 1. Introduce a concept with "garbage" files, which git is "permitted to
>> delete" without prompting.
>>
>> 2. Retain the current default, i.e. "ignored files are garbage" for now,
>> making the new behavior _opt in_ to avoid breaking automated
>> systems/existing scripts for anyone. Put the setting for this behind a
>> new core.* config flag.
>>
>> 3. In the plan for version 3.0 (a new major version where some breakage
>> can be tolerable, according to Semantic Versioning), change the default
>> so that "only explicit garbage is garbage". Include very clear notices
>> of this in the release notes. The config flag is retained, but its
>> default changes from true->false or vice versa. People who dislike the
>> new behavior can easily change back to the 2.x semantics.
>
> How does this garbage thing interact with "git clean -x"? My
> interpretation of this flag/attribute is that at version 3.0 by
> default all ignored files are _not_ garbage, so "git clean -x" should
> not remove any of them. Which is weird because most of ignored files
> are like *.o that should be removed.
>
> I also need to mark "precious" on untracked or even tracked files (*).
> Not sure how this "garbage" attribute interacts with that.
>
> (*) I was hoping I could get the idea [1] implemented in somewhat good
> shape before presenting here. But I'm a bit slow on that front. So
> yeah this "precious" on untracked/tracked thingy may be even
> irrelevant if the patch series will be rejected.

I think a garbage (or trashable) flag, if implemented, wouldn't need any
special case in git-clean, i.e. -x would remove all untracked files,
whether ignored or garbage/trashable. That's what my patch to implement
it does:
https://public-inbox.org/git/87zhuf3gs0.fsf@evledraar.gmail.com/

I think that makes sense. Users running "git clean" have "--dry-run" and
unlike "checkout a branch" or "merge this commit" where we'll now shred
data implicitly it's obvious that git-clean is going to shred your data.

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26  9:30  5%       ` Per Lundberg
  2018-11-26 10:28  5%         ` Ævar Arnfjörð Bjarmason
  2018-11-26 12:49 12%         ` Junio C Hamano
@ 2018-11-26 15:26 11%         ` Duy Nguyen
  2018-11-26 15:34  6%           ` Ævar Arnfjörð Bjarmason
  2 siblings, 1 reply; 200+ results
From: Duy Nguyen @ 2018-11-26 15:26 UTC (permalink / raw)
  To: per.lundberg
  Cc: brian m. carlson, Git Mailing List, jost, Joshua Jensen,
	Junio C Hamano, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard, Ævar Arnfjörð Bjarmason

On Mon, Nov 26, 2018 at 10:30 AM Per Lundberg <per.lundberg@hibox.tv> wrote:
>
> On 11/13/18 1:22 AM, brian m. carlson wrote:
> > This is going to totally hose automation.  My last job had files which
> > might move from tracked to untracked (a file that had become generated),
> > and long-running CI and build systems would need to be able to check out
> > one status and switch to the other.  Your proposed change will prevent
> > those systems from working, whereas they previously did.
> >
> > I agree that your proposal would have been a better design originally,
> > but breaking the way automated systems currently work is probably going
> > to be a dealbreaker.
>
> How about something like this:
>
> 1. Introduce a concept with "garbage" files, which git is "permitted to
> delete" without prompting.
>
> 2. Retain the current default, i.e. "ignored files are garbage" for now,
> making the new behavior _opt in_ to avoid breaking automated
> systems/existing scripts for anyone. Put the setting for this behind a
> new core.* config flag.
>
> 3. In the plan for version 3.0 (a new major version where some breakage
> can be tolerable, according to Semantic Versioning), change the default
> so that "only explicit garbage is garbage". Include very clear notices
> of this in the release notes. The config flag is retained, but its
> default changes from true->false or vice versa. People who dislike the
> new behavior can easily change back to the 2.x semantics.

How does this garbage thing interact with "git clean -x"? My
interpretation of this flag/attribute is that at version 3.0 by
default all ignored files are _not_ garbage, so "git clean -x" should
not remove any of them. Which is weird because most of ignored files
are like *.o that should be removed.

I also need to mark "precious" on untracked or even tracked files (*).
Not sure how this "garbage" attribute interacts with that.

(*) I was hoping I could get the idea [1] implemented in somewhat good
shape before presenting here. But I'm a bit slow on that front. So
yeah this "precious" on untracked/tracked thingy may be even
irrelevant if the patch series will be rejected.

[1] https://public-inbox.org/git/CACsJy8C3rOFv0kQeJrWufQQzbnfU4mSxJtphEYBGMmrroFFN-A@mail.gmail.com/

> Would this be a reasonable compromise for everybody?
-- 
Duy

^ permalink raw reply	[relevance 11%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26  9:30  5%       ` Per Lundberg
  2018-11-26 10:28  5%         ` Ævar Arnfjörð Bjarmason
@ 2018-11-26 12:49 12%         ` Junio C Hamano
  2018-11-27 15:08 10%           ` Ævar Arnfjörð Bjarmason
  2018-11-26 15:26 11%         ` Duy Nguyen
  2 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2018-11-26 12:49 UTC (permalink / raw)
  To: Per Lundberg
  Cc: brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Matthieu Moy, Clemens Buchacher, Holger Hellmuth,
	Kevin Ballard, Ævar Arnfjörð Bjarmason,
	Nguyễn Thái Ngọc Duy

Per Lundberg <per.lundberg@hibox.tv> writes:

> How about something like this:
> ...
> Would this be a reasonable compromise for everybody?

I do not think you'd need to introduce such a deliberately breaking
change at all.  Just introduce a new "precious" class, perhaps mark
them with the atttribute mechanism, and that would be the endgame.
Early adopters would start marking ignored but not expendable paths
with the "precious" attribute and they won't be clobbered.  As the
mechanism becomes widely known and mature, more and more people use
it.  And even after that happens, early adopters do not have to change
any attribute setting, and late adopters would have plenty of examples
to imitate.  Those who do not need any "precious" class do not have
to do anything and you won't break any existing automation that way.




^ permalink raw reply	[relevance 12%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-26  9:30  5%       ` Per Lundberg
@ 2018-11-26 10:28  5%         ` Ævar Arnfjörð Bjarmason
  2018-11-26 12:49 12%         ` Junio C Hamano
  2018-11-26 15:26 11%         ` Duy Nguyen
  2 siblings, 0 replies; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-26 10:28 UTC (permalink / raw)
  To: Per Lundberg
  Cc: brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Junio C Hamano, Matthieu Moy, Clemens Buchacher,
	Holger Hellmuth, Kevin Ballard,
	Nguyễn Thái Ngọc Duy


On Mon, Nov 26 2018, Per Lundberg wrote:

> On 11/13/18 1:22 AM, brian m. carlson wrote:
>> This is going to totally hose automation.  My last job had files which
>> might move from tracked to untracked (a file that had become generated),
>> and long-running CI and build systems would need to be able to check out
>> one status and switch to the other.  Your proposed change will prevent
>> those systems from working, whereas they previously did.
>>
>> I agree that your proposal would have been a better design originally,
>> but breaking the way automated systems currently work is probably going
>> to be a dealbreaker.
>
> How about something like this:
>
> 1. Introduce a concept with "garbage" files, which git is "permitted to
> delete" without prompting.
>
> 2. Retain the current default, i.e. "ignored files are garbage" for now,
> making the new behavior _opt in_ to avoid breaking automated
> systems/existing scripts for anyone. Put the setting for this behind a
> new core.* config flag.
>
> 3. In the plan for version 3.0 (a new major version where some breakage
> can be tolerable, according to Semantic Versioning), change the default
> so that "only explicit garbage is garbage". Include very clear notices
> of this in the release notes. The config flag is retained, but its
> default changes from true->false or vice versa. People who dislike the
> new behavior can easily change back to the 2.x semantics.
>
> Would this be a reasonable compromise for everybody?

Possibly, but I think there's an earlier step zero there for anyone
interested in pursuing this (and currently I can't make time for it),
which is to submit a patch with tests and documentation showing exactly
the sort of scenarios where we clobber or don't clobber existing files.

As my https://public-inbox.org/git/87zhuf3gs0.fsf@evledraar.gmail.com/
shows we have tests for this, but they're not explicit, and some want to
test some unrelated thing.

I.e. to test the cases where we clobber foo.c because foo.c now
explicitly exists, or cases where dir/foo.c is clobbered because "dir"
is now a tracked text file etc., are those the only two cases? I vaguely
suspect that there were other interesting cases, but at this point the
information has been paged out of the working set of my wetware. The
thread at
https://public-inbox.org/git/87o9au39s7.fsf@evledraar.gmail.com/ has
some notes about this.

Then as noted in
https://public-inbox.org/git/87wopj3661.fsf@evledraar.gmail.com/ the
reason we have this behavior seems to be something that grew organically
from a semi-related bugfix.

So I don't think we're at a point where we're all dug into our trenches
and some people want X and others want Y and in the name of backwards
compatibility we're going to stay with X. It may turn out that we just
want to retain 10% of X, and can get 99% of the safety of Y by doing
that.

^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12 23:22  5%     ` brian m. carlson
@ 2018-11-26  9:30  5%       ` Per Lundberg
  2018-11-26 10:28  5%         ` Ævar Arnfjörð Bjarmason
                           ` (2 more replies)
  2018-11-26 16:02  6%       ` Eckhard Maaß
  1 sibling, 3 replies; 200+ results
From: Per Lundberg @ 2018-11-26  9:30 UTC (permalink / raw)
  To: brian m. carlson, git@vger.kernel.org, Steffen Jost,
	Joshua Jensen, Junio C Hamano, Matthieu Moy, Clemens Buchacher,
	Holger Hellmuth, Kevin Ballard
  Cc: Ævar Arnfjörð Bjarmason,
	Nguyễn Thái Ngọc Duy

On 11/13/18 1:22 AM, brian m. carlson wrote:
> This is going to totally hose automation.  My last job had files which
> might move from tracked to untracked (a file that had become generated),
> and long-running CI and build systems would need to be able to check out
> one status and switch to the other.  Your proposed change will prevent
> those systems from working, whereas they previously did.
> 
> I agree that your proposal would have been a better design originally,
> but breaking the way automated systems currently work is probably going
> to be a dealbreaker.

How about something like this:

1. Introduce a concept with "garbage" files, which git is "permitted to 
delete" without prompting.

2. Retain the current default, i.e. "ignored files are garbage" for now, 
making the new behavior _opt in_ to avoid breaking automated 
systems/existing scripts for anyone. Put the setting for this behind a 
new core.* config flag.

3. In the plan for version 3.0 (a new major version where some breakage 
can be tolerable, according to Semantic Versioning), change the default 
so that "only explicit garbage is garbage". Include very clear notices 
of this in the release notes. The config flag is retained, but its 
default changes from true->false or vice versa. People who dislike the 
new behavior can easily change back to the 2.x semantics.

Would this be a reasonable compromise for everybody?
-- 
Per Lundberg


^ permalink raw reply	[relevance 5%]

* Re: git overwriting local ignored files?
  2018-11-24 15:41  0%       ` Konstantin Khomoutov
@ 2018-11-25  2:06  0%         ` David Mandelberg
  0 siblings, 0 replies; 200+ results
From: David Mandelberg @ 2018-11-25  2:06 UTC (permalink / raw)
  To: Konstantin Khomoutov; +Cc: Junio C Hamano, git

On 11/24/18 10:41 AM, Konstantin Khomoutov wrote:
> On Sat, Nov 24, 2018 at 05:57:24PM +0300, Konstantin Khomoutov wrote:
>> On Sat, Nov 24, 2018 at 09:37:06AM -0500, David Mandelberg wrote:
>>
>>>>> It seems that git is overwriting my local files on merge if they're in
>>>>> .gitignore.
>> [...]
>>>> The .gitignore file is to list "ignored and expendable" class of
>>>> files; there is no "ignored but precious class" in Git.
>>> Ok. Would a patch be welcome? I have three ideas for how to implement it,
>>> and I'm not sure which is better.
>> [...]
>>
>> You might want to first investigate this recent thread [1] which AFAIK
>> was dedicated to exactly this problem.
> 
> Well, actually the thread is old, but its continuation [2] is recent.
> The crux is that it discusses certain approaches to solve the apparent
> problem and patches to do that.
> 
> 1. https://public-inbox.org/git/4C6A1C5B.4030304@workspacewhiz.com/
> 2. https://public-inbox.org/git/871s8qdzph.fsf@evledraar.gmail.com/

Thanks for the pointers, and sorry to start a new thread. It looks like 
most of the work to do is in finding consensus on the right way forward, 
rather than in writing a patch. While I really would like there be a way 
to prevent git from overwriting ignored files, I don't have any strong 
opinions on what that way should look like. So I think I'll just wait 
and hope somebody else does the work.

-- 
https://david.mandelberg.org/

^ permalink raw reply	[relevance 0%]

* Re: git overwriting local ignored files?
  2018-11-24 14:57  0%     ` Konstantin Khomoutov
@ 2018-11-24 15:41  0%       ` Konstantin Khomoutov
  2018-11-25  2:06  0%         ` David Mandelberg
  0 siblings, 1 reply; 200+ results
From: Konstantin Khomoutov @ 2018-11-24 15:41 UTC (permalink / raw)
  To: David Mandelberg; +Cc: Junio C Hamano, git

On Sat, Nov 24, 2018 at 05:57:24PM +0300, Konstantin Khomoutov wrote:
> On Sat, Nov 24, 2018 at 09:37:06AM -0500, David Mandelberg wrote:
> 
> > > > It seems that git is overwriting my local files on merge if they're in
> > > > .gitignore.
> [...]
> > > The .gitignore file is to list "ignored and expendable" class of
> > > files; there is no "ignored but precious class" in Git.
> > Ok. Would a patch be welcome? I have three ideas for how to implement it,
> > and I'm not sure which is better.
> [...]
> 
> You might want to first investigate this recent thread [1] which AFAIK
> was dedicated to exactly this problem.

Well, actually the thread is old, but its continuation [2] is recent.
The crux is that it discusses certain approaches to solve the apparent
problem and patches to do that.

1. https://public-inbox.org/git/4C6A1C5B.4030304@workspacewhiz.com/
2. https://public-inbox.org/git/871s8qdzph.fsf@evledraar.gmail.com/


^ permalink raw reply	[relevance 0%]

* Re: git overwriting local ignored files?
  2018-11-24 14:37  6%   ` David Mandelberg
@ 2018-11-24 14:57  0%     ` Konstantin Khomoutov
  2018-11-24 15:41  0%       ` Konstantin Khomoutov
  0 siblings, 1 reply; 200+ results
From: Konstantin Khomoutov @ 2018-11-24 14:57 UTC (permalink / raw)
  To: David Mandelberg; +Cc: Junio C Hamano, git

On Sat, Nov 24, 2018 at 09:37:06AM -0500, David Mandelberg wrote:

> > > It seems that git is overwriting my local files on merge if they're in
> > > .gitignore.
[...]
> > The .gitignore file is to list "ignored and expendable" class of
> > files; there is no "ignored but precious class" in Git.
> Ok. Would a patch be welcome? I have three ideas for how to implement it,
> and I'm not sure which is better.
[...]

You might want to first investigate this recent thread [1] which AFAIK
was dedicated to exactly this problem.

1. https://public-inbox.org/git/4C6A1C5B.4030304@workspacewhiz.com/


^ permalink raw reply	[relevance 0%]

* Re: git overwriting local ignored files?
  2018-11-24  4:22  4% ` Junio C Hamano
@ 2018-11-24 14:37  6%   ` David Mandelberg
  2018-11-24 14:57  0%     ` Konstantin Khomoutov
  0 siblings, 1 reply; 200+ results
From: David Mandelberg @ 2018-11-24 14:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 11/23/18 11:22 PM, Junio C Hamano wrote:
> David Mandelberg <david@mandelberg.org> writes:
> 
>> It seems that git is overwriting my local files on merge if they're in
>> .gitignore. See command transcript below. I searched `git help config`
>> and Google, but I couldn't find any way to prevent it. Am I missing
>> something? (The reason I care about ignored files is that I'm using
>> git with a working directory of $HOME to manage my dotfiles, and most
>> files in my $HOME are not tracked by git but are still important.)
> 
> The .gitignore file is to list "ignored and expendable" class of
> files; there is no "ignored but precious class" in Git.

Ok. Would a patch be welcome? I have three ideas for how to implement 
it, and I'm not sure which is better.

1. Add a boolean config option called core.preserveIgnore (or similar). 
I'm guessing this is the least amount of work, but it's not very 
flexible. I'm also not sure how it should work with `git clean`.

2. Add some syntax to the .gitignore format so the same file can list 
both "ignored and expendable" and "ignored and precious". I could see 
using this to mark compiled files as ignored+expendable and per-repo 
editor/IDE config files as ignored+precious. Do you have any idea how 
big of a patch this would be? Or any idea for the new syntax? I think 
starting a line with "\x" where x is any character not currently escaped 
by a backslash would cause the least disruption to existing .gitignore 
files.

3. Like (2), but use a separate file instead of .gitignore (and the 
other git-ignore files).

Any thoughts?

-- 
https://david.mandelberg.org/

^ permalink raw reply	[relevance 6%]

* Re: git overwriting local ignored files?
  @ 2018-11-24  4:22  4% ` Junio C Hamano
  2018-11-24 14:37  6%   ` David Mandelberg
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2018-11-24  4:22 UTC (permalink / raw)
  To: David Mandelberg; +Cc: git

David Mandelberg <david@mandelberg.org> writes:

> It seems that git is overwriting my local files on merge if they're in
> .gitignore. See command transcript below. I searched `git help config`
> and Google, but I couldn't find any way to prevent it. Am I missing
> something? (The reason I care about ignored files is that I'm using
> git with a working directory of $HOME to manage my dotfiles, and most
> files in my $HOME are not tracked by git but are still important.)

The .gitignore file is to list "ignored and expendable" class of
files; there is no "ignored but precious class" in Git.

^ permalink raw reply	[relevance 4%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11 12:33 11%   ` [RFC PATCH] Introduce "precious" file concept Ævar Arnfjörð Bjarmason
  2018-11-11 13:06  4%     ` Ævar Arnfjörð Bjarmason
  2018-11-11 15:41 11%     ` Duy Nguyen
@ 2018-11-12 23:22  5%     ` brian m. carlson
  2018-11-26  9:30  5%       ` Per Lundberg
  2018-11-26 16:02  6%       ` Eckhard Maaß
  2 siblings, 2 replies; 200+ results
From: brian m. carlson @ 2018-11-12 23:22 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Nguyễn Thái Ngọc Duy, git, Steffen Jost,
	Joshua Jensen, Per Lundberg, Junio C Hamano, Matthieu Moy,
	Clemens Buchacher, Holger Hellmuth, Kevin Ballard

[-- Attachment #1: Type: text/plain, Size: 1923 bytes --]

On Sun, Nov 11, 2018 at 01:33:44PM +0100, Ævar Arnfjörð Bjarmason wrote:
> The users who need protection against git deleting their files the most
> are exactly the sort of users who aren't expert-level enough to
> understand the nuances of how the semantics of .gitignore and "precious"
> are going to interact before git eats their data.
> 
> This is pretty apparent from the bug reports we're getting about
> this. None of them are:
> 
>     "Hey, I 100% understood .gitignore semantics including this one part
>     of the docs where you say you'll do this, but just forgot one day
>     and deleted my work. Can we get some more safety?"
> 
> But rather (with some hyperbole for effect):
> 
>     "ZOMG git deleted my file! Is this a bug??"
> 
> So I think we should have the inverse of this "precious"
> attribute". Just a change to the docs to say that .gitignore doesn't
> imply these eager deletion semantics on tree unpacking anymore, and if
> users want it back they can define a "garbage" attribute
> (s/precious/garbage/).
> 
> That will lose no data, and in the very rare cases where a checkout of
> tracked files would overwrite an ignored pattern, we can just error out
> (as we do with the "Ok to overwrite" branch removed) and tell the user
> to delete the files to proceed.

This is going to totally hose automation.  My last job had files which
might move from tracked to untracked (a file that had become generated),
and long-running CI and build systems would need to be able to check out
one status and switch to the other.  Your proposed change will prevent
those systems from working, whereas they previously did.

I agree that your proposal would have been a better design originally,
but breaking the way automated systems currently work is probably going
to be a dealbreaker.
-- 
brian m. carlson: Houston, Texas, US
OpenPGP: https://keybase.io/bk2204

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 868 bytes --]

^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11 13:06  4%     ` Ævar Arnfjörð Bjarmason
@ 2018-11-12 16:14  6%       ` Duy Nguyen
  0 siblings, 0 replies; 200+ results
From: Duy Nguyen @ 2018-11-12 16:14 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, jost, Joshua Jensen, per.lundberg,
	Junio C Hamano, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

On Sun, Nov 11, 2018 at 2:06 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
> +Trashable files
> +~~~~~~~~~~~~~~~
> +
> +`trashable`
> +^^^^^^^^^^
> +
> +Provides an escape hatch for re-enabling a potentially data destroying
> +feature which was enabled by default between Git versions 1.5.2 and
> +2.20. See the `NOTES` section of linkgit:gitignore[5] for details.

How does this interact with "git clean -x"? Most ignored files will
not have trashable attribute, so we don't remove any of them? Making
"git clean" completely ignore this attribute is also possible, I
guess, if we rename it somehow to avoid confusion.
-- 
Duy

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12  9:08 12%         ` Matthieu Moy
  2018-11-12  9:49  4%           ` Ævar Arnfjörð Bjarmason
@ 2018-11-12 16:07  5%           ` Duy Nguyen
  1 sibling, 0 replies; 200+ results
From: Duy Nguyen @ 2018-11-12 16:07 UTC (permalink / raw)
  To: git
  Cc: per.lundberg, Ævar Arnfjörð Bjarmason,
	Git Mailing List, jost, Joshua Jensen, Junio C Hamano,
	Clemens Buchacher, Holger Hellmuth (IKS), Kevin Ballard

On Mon, Nov 12, 2018 at 10:09 AM Matthieu Moy <git@matthieu-moy.fr> wrote:
> May I remind an idea I sugested in an old thread: add an intermediate level
> where ignored files to be overwritten are renamed (eg. foo -> foo~ like Emacs'
> backup files):
>
> https://public-inbox.org/git/vpqd3t9656k.fsf@bauges.imag.fr/
>
> One advantage of the "rename" behavior is that it's safer that the current,
> but still not very disturbing for people who like the current behavior. This
> makes it a good candidate for a default behavior.

I have something else in the bag that does something like this. The
idea is that we go ahead and do destructive things but we let the user
undo.

Some more background in [1] but basically we hash "every" change and
store in the object database (in this case we store "foo" content
before overwriting it). We maintain a list of these hashes so that
undo is possible, but of course we don't keep infinite change history,
eventually too old changes will be pruned. [1] talks about index
changes (e.g. "git add -p") but it could apply to worktree changes as
well (and I'm also eyeing $GIT_DIR/config changes).

The upside: a similar undo mechanism that works for more than just
this case and it allows undoing multiple times while foo~ only allow
once. The downside: hashing is definitely heavier than renaming foo to
foo~. So this will feature be opt-in in most cases. But for
"dangerous" overwrite like this case, I think we value the file
content more and make it opt-out.

[1] https://public-inbox.org/git/CACsJy8A3QCYY6QeJQYkbCKYh=7Q7pj=rer_OQHLGoAMqTNomNA@mail.gmail.com/
-- 
Duy

^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12 12:45  6%               ` Ævar Arnfjörð Bjarmason
@ 2018-11-12 13:02  6%                 ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2018-11-12 13:02 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Matthieu Moy, Per Lundberg, Duy Nguyen, Git Mailing List, jost,
	Joshua Jensen, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

>> Or only selected "*.o" (vendor supplied binary blob) kept tracked
>> while everything else is built from the source.
>> ...
> But it also does get used for "mostly we don't want this file, but
> sometimes we do" use-case, so that's something we need to deal with in
> practice.

Exactly.  "Mostly we don't want *.o as we prefer to build from the
source, but we have only object files for some selected ones" is an
often cited use case where it is the BCP to have *.o in .gitignore
and use "add -f" to add the "selected" ones initially.


^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12 10:26  6%             ` Junio C Hamano
@ 2018-11-12 12:45  6%               ` Ævar Arnfjörð Bjarmason
  2018-11-12 13:02  6%                 ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-12 12:45 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Matthieu Moy, Per Lundberg, Duy Nguyen, Git Mailing List, jost,
	Joshua Jensen, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard


On Mon, Nov 12 2018, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:
>
>> What I'd add to your list is:
>>
>> * Some projects (I've seen this in the wild) add e.g. *.mp3 or whatever
>>   else usually doesn't belong in the repo as a "soft ignore". This is
>>   something we've never recommended, but have implicitly supported since
>>   the only caveats are a) you need a one-off "git add -f" and then
>>   they're tracked b) them being missing from "status" before being
>>   tracked c) the issue under discussion here.
>
> Or only selected "*.o" (vendor supplied binary blob) kept tracked
> while everything else is built from the source.
>
> I do not know who you are referring to "we" in your sentence, but as
> far as I am concerned, it has been and still is a BCP recommendation
> on this list to deal with a case like that.

I mean that this use-case of having a "soft" ignore by carrying it
across the "git add" barrier with a one-off "-f" isn't something
explicitly documented, and apparently not something many
expect. I.e. you / Matthieu have mentioned .gitignore in the past for
only-generated *.o use-case.

But it also does get used for "mostly we don't want this file, but
sometimes we do" use-case, so that's something we need to deal with in
practice. Like many workflows in git it's not something that was forseen
or intended, but does happen in the wild.

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12  9:49  4%           ` Ævar Arnfjörð Bjarmason
@ 2018-11-12 10:26  6%             ` Junio C Hamano
  2018-11-12 12:45  6%               ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2018-11-12 10:26 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Matthieu Moy, Per Lundberg, Duy Nguyen, Git Mailing List, jost,
	Joshua Jensen, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> What I'd add to your list is:
>
> * Some projects (I've seen this in the wild) add e.g. *.mp3 or whatever
>   else usually doesn't belong in the repo as a "soft ignore". This is
>   something we've never recommended, but have implicitly supported since
>   the only caveats are a) you need a one-off "git add -f" and then
>   they're tracked b) them being missing from "status" before being
>   tracked c) the issue under discussion here.

Or only selected "*.o" (vendor supplied binary blob) kept tracked
while everything else is built from the source.

I do not know who you are referring to "we" in your sentence, but as
far as I am concerned, it has been and still is a BCP recommendation
on this list to deal with a case like that.

^ permalink raw reply	[relevance 6%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12  7:35 11%       ` Per Lundberg
@ 2018-11-12  9:08 12%         ` Matthieu Moy
  2018-11-12  9:49  4%           ` Ævar Arnfjörð Bjarmason
  2018-11-12 16:07  5%           ` Duy Nguyen
  0 siblings, 2 replies; 200+ results
From: Matthieu Moy @ 2018-11-12  9:08 UTC (permalink / raw)
  To: Per Lundberg
  Cc: Duy Nguyen, Ævar Arnfjörð Bjarmason,
	Git Mailing List, jost, Joshua Jensen, Junio C Hamano,
	Clemens Buchacher, Holger Hellmuth (IKS), Kevin Ballard

"Per Lundberg" <per.lundberg@hibox.tv> wrote:

> On 11/11/18 5:41 PM, Duy Nguyen wrote:
> > On Sun, Nov 11, 2018 at 1:33 PM Ævar Arnfjörð Bjarmason
> > <avarab@gmail.com> wrote:
>
> >> That will lose no data, and in the very rare cases where a checkout of
> >> tracked files would overwrite an ignored pattern, we can just error out
> >> (as we do with the "Ok to overwrite" branch removed) and tell the user
> >> to delete the files to proceed.
> > There's also the other side of the coin. If this refuse to overwrite
> > triggers too often, it can become an annoyance.

I may have missed some cases, but to me the cases when checkout may try
to overwrite an ignored file are essentially:

* Someone "git add"ed a file meant to be ignored by mistake (e.g.
  "git add -f *.o").

* A file that was meant to be kept private (e.g. config.mak.dev) ends
  up being tracked. This may happen when we find a way to make per-developer
  settings the same for everyone.

I both cases I'd want at least to be notified that something is going on,
and in the second I'd probably want to keep my local file around.

> If we feel thrashable is stretching it too far (which I don't think it
> is), we could add a "core.ignore_files_are_trashable" setting that
> brings back the old semantics, for those who have a strong feeling about it.

May I remind an idea I sugested in an old thread: add an intermediate level
where ignored files to be overwritten are renamed (eg. foo -> foo~ like Emacs'
backup files):

https://public-inbox.org/git/vpqd3t9656k.fsf@bauges.imag.fr/

One advantage of the "rename" behavior is that it's safer that the current,
but still not very disturbing for people who like the current behavior. This
makes it a good candidate for a default behavior.

This could come in complement with this thread's "precious" concept:

* If you know what you're doing and know that such or such file is precious,
  mark it as such and Git will never overwrite it.

* If you don't know about precious files, just keep the default setting and
  the worse that can happen is to get your file overwritten with a bakup
  of the old version kept around.

This would probably play better with a notion of "precious" files than with
a notion of "trashable" files.

-- 
Matthieu Moy
https://matthieu-moy.fr/

^ permalink raw reply	[relevance 12%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-12  9:08 12%         ` Matthieu Moy
@ 2018-11-12  9:49  4%           ` Ævar Arnfjörð Bjarmason
  2018-11-12 10:26  6%             ` Junio C Hamano
  2018-11-12 16:07  5%           ` Duy Nguyen
  1 sibling, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-12  9:49 UTC (permalink / raw)
  To: Matthieu Moy
  Cc: Per Lundberg, Duy Nguyen, Git Mailing List, jost, Joshua Jensen,
	Junio C Hamano, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard


On Mon, Nov 12 2018, Matthieu Moy wrote:

> "Per Lundberg" <per.lundberg@hibox.tv> wrote:
>
>> On 11/11/18 5:41 PM, Duy Nguyen wrote:
>> > On Sun, Nov 11, 2018 at 1:33 PM Ævar Arnfjörð Bjarmason
>> > <avarab@gmail.com> wrote:
>>
>> >> That will lose no data, and in the very rare cases where a checkout of
>> >> tracked files would overwrite an ignored pattern, we can just error out
>> >> (as we do with the "Ok to overwrite" branch removed) and tell the user
>> >> to delete the files to proceed.
>> > There's also the other side of the coin. If this refuse to overwrite
>> > triggers too often, it can become an annoyance.
>
> I may have missed some cases, but to me the cases when checkout may try
> to overwrite an ignored file are essentially:
>
> * Someone "git add"ed a file meant to be ignored by mistake (e.g.
>   "git add -f *.o").
>
> * A file that was meant to be kept private (e.g. config.mak.dev) ends
>   up being tracked. This may happen when we find a way to make per-developer
>   settings the same for everyone.

Yes, the cases under discussion here are all cases where a tracked file
clobbers a file matching a pattern in in .gitignore.

What I'd add to your list is:

* Some projects (I've seen this in the wild) add e.g. *.mp3 or whatever
  else usually doesn't belong in the repo as a "soft ignore". This is
  something we've never recommended, but have implicitly supported since
  the only caveats are a) you need a one-off "git add -f" and then
  they're tracked b) them being missing from "status" before being
  tracked c) the issue under discussion here.

* Cases where e.g. filename changes to a directory or globs because of
  that make this more complex.

> I both cases I'd want at least to be notified that something is going on,
> and in the second I'd probably want to keep my local file around.
>> If we feel thrashable is stretching it too far (which I don't think it
>> is), we could add a "core.ignore_files_are_trashable" setting that
>> brings back the old semantics, for those who have a strong feeling about it.
>
> May I remind an idea I sugested in an old thread: add an intermediate level
> where ignored files to be overwritten are renamed (eg. foo -> foo~ like Emacs'
> backup files):
>
> https://public-inbox.org/git/vpqd3t9656k.fsf@bauges.imag.fr/
>
> One advantage of the "rename" behavior is that it's safer that the current,
> but still not very disturbing for people who like the current behavior. This
> makes it a good candidate for a default behavior.
>
> This could come in complement with this thread's "precious" concept:
>
> * If you know what you're doing and know that such or such file is precious,
>   mark it as such and Git will never overwrite it.
>
> * If you don't know about precious files, just keep the default setting and
>   the worse that can happen is to get your file overwritten with a bakup
>   of the old version kept around.
>
> This would probably play better with a notion of "precious" files than with
> a notion of "trashable" files.

I used to think this foo -> foo~ approach made the most sense (and said
as much in
https://public-inbox.org/git/871s8qdzph.fsf@evledraar.gmail.com/) but I
think it's probably best not to do it and just error out, because:

 * We'd still need to handle the cases where "tests" the file collides
   with "tests" the directory. Then where do we move the colliding file?
   ~/.git/lost+found/* ? We could handle the subdir case with another
   special-case though...

 * I think such silent action will just leave users more confused, and
   in many cases (e.g. a merge) whatever message we print out will be
   missed in a deluge of other messaging, and they'll probably miss it.

   I'd like to avoid a case where a bunch of *~ files get committed
   because the user's workflow is (and some beginner git users do this):

       git pull && git add . && git commit && git push

   As the "pull" would now invoke a merge that would do this rename.

 * If I have the "foo" file open in my editor (a plausible way to run
   into this) I switch to another terminal, do the merge, miss the
   message, then re-save "foo". Now I have both "foo" and "foo~"
   on-disk. Another case where we should just refuse until the user
   resolves the situation to avoid the confusion.

^ permalink raw reply	[relevance 4%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11 15:41 11%     ` Duy Nguyen
  2018-11-11 16:55  5%       ` Ævar Arnfjörð Bjarmason
@ 2018-11-12  7:35 11%       ` Per Lundberg
  2018-11-12  9:08 12%         ` Matthieu Moy
  1 sibling, 1 reply; 200+ results
From: Per Lundberg @ 2018-11-12  7:35 UTC (permalink / raw)
  To: Duy Nguyen, Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, jost@tcs.ifi.lmu.de, Joshua Jensen,
	Junio C Hamano, git@matthieu-moy.fr, Clemens Buchacher,
	Holger Hellmuth (IKS), Kevin Ballard

On 11/11/18 5:41 PM, Duy Nguyen wrote:
> On Sun, Nov 11, 2018 at 1:33 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
 >
>> That will lose no data, and in the very rare cases where a checkout of
>> tracked files would overwrite an ignored pattern, we can just error out
>> (as we do with the "Ok to overwrite" branch removed) and tell the user
>> to delete the files to proceed. 
> There's also the other side of the coin. If this refuse to overwrite
> triggers too often, it can become an annoyance.

Sure, but doing "git checkout -f some_ref" instead of "git checkout 
some_ref" isn't really _that_ annoying, is it? I think, people (because 
of not having read/studied the .gitignore semantics well enough) having 
their files being overwritten _without realizing it_ is a bigger danger. 
But obviously there is a bit of treading a thin line here.

If we feel thrashable is stretching it too far (which I don't think it 
is), we could add a "core.ignore_files_are_trashable" setting that 
brings back the old semantics, for those who have a strong feeling about it.

It's also quite possible to do it the other way around - i.e. set 
"core.ignore_files_are_trashable" to true by default, and let the "new" 
behavior be opt-in. However, this might "miss the mark" in that those 
people who would really benefit from the new semantics might miss this 
setting, just like they could risk missing the "precious" setting.

(I also think "trashable" sounds better and is more clear & precise than 
"precious", for whatever that is worth.)
--
Per Lundberg

^ permalink raw reply	[relevance 11%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11 15:41 11%     ` Duy Nguyen
@ 2018-11-11 16:55  5%       ` Ævar Arnfjörð Bjarmason
  2018-11-12  7:35 11%       ` Per Lundberg
  1 sibling, 0 replies; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-11 16:55 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Git Mailing List, jost, Joshua Jensen, per.lundberg,
	Junio C Hamano, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard


On Sun, Nov 11 2018, Duy Nguyen wrote:

> On Sun, Nov 11, 2018 at 1:33 PM Ævar Arnfjörð Bjarmason
> <avarab@gmail.com> wrote:
>> The users who need protection against git deleting their files the most
>> are exactly the sort of users who aren't expert-level enough to
>> understand the nuances of how the semantics of .gitignore and "precious"
>> are going to interact before git eats their data.
>>
>> This is pretty apparent from the bug reports we're getting about
>> this. None of them are:
>>
>>     "Hey, I 100% understood .gitignore semantics including this one part
>>     of the docs where you say you'll do this, but just forgot one day
>>     and deleted my work. Can we get some more safety?"
>>
>> But rather (with some hyperbole for effect):
>>
>>     "ZOMG git deleted my file! Is this a bug??"
>>
>> So I think we should have the inverse of this "precious"
>> attribute". Just a change to the docs to say that .gitignore doesn't
>> imply these eager deletion semantics on tree unpacking anymore, and if
>> users want it back they can define a "garbage" attribute
>> (s/precious/garbage/).
>>
>> That will lose no data, and in the very rare cases where a checkout of
>> tracked files would overwrite an ignored pattern, we can just error out
>> (as we do with the "Ok to overwrite" branch removed) and tell the user
>> to delete the files to proceed.
>
> There's also the other side of the coin. If this refuse to overwrite
> triggers too often, it can become an annoyance. So far I've seen two
> reports of accident overwriting which make me think turning precious
> to trashable may be too extreme. Plus ignored files are trashable by
> default (or at least by design so far), adding trashable attribute
> changes how we handle ignored files quite significantly.

Yeah I'm not trying to make the argument that we should just go with
these user bug reports, clearly that's just going to give us selection
bias and we could continue to flip between the two behaviors with that
approach. Just that an advanced opt-in feature to prevent dataloss will
not prevent it in practice.

Is taking my patch the right thing? I don't know. I'm leaning in that
direction, but more making a devil's advocate argument to see if anyone
finds good cases that'll demonstrate how it's bad. I haven't read/seen
them so far, and the test suite didn't have any.

I did go through the list archives as Junio suggested in
https://public-inbox.org/git/7viq39avay.fsf@alter.siamese.dyndns.org/
and found these two:
https://public-inbox.org/git/?q=d%3A20070301..20070331+verify_absent

It seems to me that the reason we ended up with this behavior is a bug
report from Shawn that was describing a similar but not quite the same
problem:

    "[...]a bug in read-tree -m that prevents him from switching
    branches when the type of a path changes between a directory and a
    file.[...]"

That's not the same as when a now-tracked file clobbers a .gitignored
file. As far as I can tell (but may not have read carefully enough) that
wasn't a problem anyone reported, but was changed while fixing another
bug in c81935348b ("Fix switching to a branch with D/F when current
branch has file D.", 2007-03-15).

^ permalink raw reply	[relevance 5%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11 12:33 11%   ` [RFC PATCH] Introduce "precious" file concept Ævar Arnfjörð Bjarmason
  2018-11-11 13:06  4%     ` Ævar Arnfjörð Bjarmason
@ 2018-11-11 15:41 11%     ` Duy Nguyen
  2018-11-11 16:55  5%       ` Ævar Arnfjörð Bjarmason
  2018-11-12  7:35 11%       ` Per Lundberg
  2018-11-12 23:22  5%     ` brian m. carlson
  2 siblings, 2 replies; 200+ results
From: Duy Nguyen @ 2018-11-11 15:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, jost, Joshua Jensen, per.lundberg,
	Junio C Hamano, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

On Sun, Nov 11, 2018 at 1:33 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
> The users who need protection against git deleting their files the most
> are exactly the sort of users who aren't expert-level enough to
> understand the nuances of how the semantics of .gitignore and "precious"
> are going to interact before git eats their data.
>
> This is pretty apparent from the bug reports we're getting about
> this. None of them are:
>
>     "Hey, I 100% understood .gitignore semantics including this one part
>     of the docs where you say you'll do this, but just forgot one day
>     and deleted my work. Can we get some more safety?"
>
> But rather (with some hyperbole for effect):
>
>     "ZOMG git deleted my file! Is this a bug??"
>
> So I think we should have the inverse of this "precious"
> attribute". Just a change to the docs to say that .gitignore doesn't
> imply these eager deletion semantics on tree unpacking anymore, and if
> users want it back they can define a "garbage" attribute
> (s/precious/garbage/).
>
> That will lose no data, and in the very rare cases where a checkout of
> tracked files would overwrite an ignored pattern, we can just error out
> (as we do with the "Ok to overwrite" branch removed) and tell the user
> to delete the files to proceed.

There's also the other side of the coin. If this refuse to overwrite
triggers too often, it can become an annoyance. So far I've seen two
reports of accident overwriting which make me think turning precious
to trashable may be too extreme. Plus ignored files are trashable by
default (or at least by design so far), adding trashable attribute
changes how we handle ignored files quite significantly.
-- 
Duy

^ permalink raw reply	[relevance 11%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11  9:52 20% [RFC PATCH] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
    2018-11-11 12:15 11% ` Bert Wesarg
@ 2018-11-11 12:59 12% ` Junio C Hamano
  2018-11-26 19:38  6% ` [PATCH v2 0/2] Precios files round two Nguyễn Thái Ngọc Duy
  3 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2018-11-11 12:59 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> Also while "precious" is a fun name, but it does not sound serious.
> Any suggestions? Perhaps "valuable"?

FWIW, I am reasonably sure that I was the first in Git circle who
used the term "precious" in discussions wrt .gitignore, i.e. "Git
has ignored but not precious category".  Since it was not my
invention but was a borrowed term from tla (aka GNU arch), I'd
suggest to keep using that term, unless there is a strong reason not
to follow longstanding precedent.

^ permalink raw reply	[relevance 12%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11 12:33 11%   ` [RFC PATCH] Introduce "precious" file concept Ævar Arnfjörð Bjarmason
@ 2018-11-11 13:06  4%     ` Ævar Arnfjörð Bjarmason
  2018-11-12 16:14  6%       ` Duy Nguyen
  2018-11-11 15:41 11%     ` Duy Nguyen
  2018-11-12 23:22  5%     ` brian m. carlson
  2 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-11 13:06 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Steffen Jost, Joshua Jensen, Per Lundberg, Junio C Hamano,
	Matthieu Moy, Clemens Buchacher, Holger Hellmuth, Kevin Ballard


On Sun, Nov 11 2018, Ævar Arnfjörð Bjarmason wrote:

> [CC-ing some of the people involved in recent threads about this]
>
> On Sun, Nov 11 2018, Nguyễn Thái Ngọc Duy wrote:
>
>> Since this topic has come up twice recently, I revisited this
>> "precious" thingy that I started four years ago and tried to see if I
>> could finally finish it. There are a couple things to be sorted out...
>>
>> A new attribute "precious" is added to indicate that certain files
>> have valuable content and should not be easily discarded even if they
>> are ignored or untracked (*).
>>
>> So far there are two parts of Git that are made aware of precious
>> files: "git clean" will leave precious files alone and unpack-trees.c
>> (i.e. merges and branch switches) will not overwrite
>> ignored-but-precious files.
>>
>> Is there any other parts of Git that should be made aware of this
>> "precious" attribute?
>>
>> Also while "precious" is a fun name, but it does not sound serious.
>> Any suggestions? Perhaps "valuable"?
>>
>> Very lightly tested. The patch is more to have something to discuss
>> than is bug free and ready to use.
>>
>> (*) Note that tracked files could be marked "precious" in the future
>>     too although the exact semantics is not very clear since tracked
>>     files are by default precious.
>>
>>     But something like "index log" could use this to record all
>>     changes to precious files instead of just "git add -p" changes,
>>     for example. So these files are in a sense more precious than
>>     other tracked files.
>>
>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>> ---
>>  Documentation/git-clean.txt     |  3 ++-
>>  Documentation/gitattributes.txt | 13 +++++++++++++
>>  attr.c                          |  9 +++++++++
>>  attr.h                          |  2 ++
>>  builtin/clean.c                 | 19 ++++++++++++++++---
>>  unpack-trees.c                  |  3 ++-
>>  6 files changed, 44 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
>> index 03056dad0d..a9beadfb12 100644
>> --- a/Documentation/git-clean.txt
>> +++ b/Documentation/git-clean.txt
>> @@ -21,7 +21,8 @@ option is specified, ignored files are also removed. This can, for
>>  example, be useful to remove all build products.
>>
>>  If any optional `<path>...` arguments are given, only those paths
>> -are affected.
>> +are affected. Ignored or untracked files with `precious` attributes
>> +are not removed.
>>
>>  OPTIONS
>>  -------
>> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
>> index b8392fc330..c722479bdc 100644
>> --- a/Documentation/gitattributes.txt
>> +++ b/Documentation/gitattributes.txt
>> @@ -1188,6 +1188,19 @@ If this attribute is not set or has an invalid value, the value of the
>>  (See linkgit:git-config[1]).
>>
>>
>> +Precious files
>> +~~~~~~~~~~~~~~~~~~~~~~~~
>> +
>> +`precious`
>> +^^^^^^^^^^
>> +
>> +This attribute is set on files to indicate that their content is
>> +valuable. Many commands will behave slightly different on precious
>> +files. linkgit:git-clean[1] will leave precious files alone. Merging
>> +and branch switching will not silently overwrite ignored files that
>> +are marked "precious".
>> +
>> +
>>  USING MACRO ATTRIBUTES
>>  ----------------------
>>
>> diff --git a/attr.c b/attr.c
>> index 60d284796d..d06ca0ae4b 100644
>> --- a/attr.c
>> +++ b/attr.c
>> @@ -1186,3 +1186,12 @@ void attr_start(void)
>>  	pthread_mutex_init(&check_vector.mutex, NULL);
>>  #endif
>>  }
>> +
>> +int is_precious_file(struct index_state *istate, const char *path)
>> +{
>> +	static struct attr_check *check;
>> +	if (!check)
>> +		check = attr_check_initl("precious", NULL);
>> +	git_check_attr(istate, path, check);
>> +	return check && ATTR_TRUE(check->items[0].value);
>> +}
>
> If we merge two branches is this using the merged post-image of
> .gitattributes as a source?
>
>>  	if (o->dir &&
>> -	    is_excluded(o->dir, o->src_index, name, &dtype))
>> +	    is_excluded(o->dir, o->src_index, name, &dtype) &&
>> +	    !is_precious_file(o->src_index, name))
>>  		/*
>>  		 * ce->name is explicitly excluded, so it is Ok to
>>  		 * overwrite it.
>
> I wonder if instead we should just be reverting c81935348b ("Fix
> switching to a branch with D/F when current branch has file D.",
> 2007-03-15), which these days (haven't dug deeply) would just be this,
> right?:
>
>>    diff --git a/unpack-trees.c b/unpack-trees.c
>     index 7570df481b..b3efaddd4f 100644
>     --- a/unpack-trees.c
>     +++ b/unpack-trees.c
>     @@ -1894,13 +1894,6 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
>      	if (ignore_case && icase_exists(o, name, len, st))
>      		return 0;
>
>     -	if (o->dir &&
>     -	    is_excluded(o->dir, o->src_index, name, &dtype))
>     -		/*
>     -		 * ce->name is explicitly excluded, so it is Ok to
>     -		 * overwrite it.
>     -		 */
>     -		return 0;
>      	if (S_ISDIR(st->st_mode)) {
>      		/*
>      		 * We are checking out path "foo" and
>
> Something like the approach you're taking will absolutely work from a
> technical standpoint, but I fear that it's going to be useless in
> practice.
>
> The users who need protection against git deleting their files the most
> are exactly the sort of users who aren't expert-level enough to
> understand the nuances of how the semantics of .gitignore and "precious"
> are going to interact before git eats their data.
>
> This is pretty apparent from the bug reports we're getting about
> this. None of them are:
>
>     "Hey, I 100% understood .gitignore semantics including this one part
>     of the docs where you say you'll do this, but just forgot one day
>     and deleted my work. Can we get some more safety?"
>
> But rather (with some hyperbole for effect):
>
>     "ZOMG git deleted my file! Is this a bug??"
>
> So I think we should have the inverse of this "precious"
> attribute". Just a change to the docs to say that .gitignore doesn't
> imply these eager deletion semantics on tree unpacking anymore, and if
> users want it back they can define a "garbage" attribute
> (s/precious/garbage/).
>
> That will lose no data, and in the very rare cases where a checkout of
> tracked files would overwrite an ignored pattern, we can just error out
> (as we do with the "Ok to overwrite" branch removed) and tell the user
> to delete the files to proceed.
>
> Three tests in our test suite fail with that patch applied, and they're
> explicitly testing for exactly the sort of scenario where users are likely to lose data. I.e.:
>
>  1. Open a tracked file in an editor
>  2. Save it
>  3. Switch to a topic branch, that has different .gitignore semantics
>     (e.g. let's say a build/ dir exists there)
>  4. Have their work deleted
>
> So actually in writing this out I've become convinced that this
> "precious" approach can't work either, because *even if* you're an
> expert who manages to perfectly define their .gitignore and "precious"
> rules in advance to avoid data deletion, those rules will *also* need to
> take into account switching between branches (or even different
> histories) where you have other sorts of rules.
>
> So really, if there's ambiguity let's just not delete stuff by default
> and ask the user to resolve it.

Here's a patch to implement that (which borrows from some of yours). It
passes all of our tests:

diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index b8392fc330..a6cad17899 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -1188,6 +1188,17 @@ If this attribute is not set or has an invalid value, the value of the
 (See linkgit:git-config[1]).


+Trashable files
+~~~~~~~~~~~~~~~
+
+`trashable`
+^^^^^^^^^^
+
+Provides an escape hatch for re-enabling a potentially data destroying
+feature which was enabled by default between Git versions 1.5.2 and
+2.20. See the `NOTES` section of linkgit:gitignore[5] for details.
+
+
 USING MACRO ATTRIBUTES
 ----------------------

diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index d107daaffd..39c6d5955a 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -140,6 +140,13 @@ not tracked by Git remain untracked.
 To stop tracking a file that is currently tracked, use
 'git rm --cached'.

+Between Git versions 1.5.2 and 2.20 untracked files or directories
+which were ignored and conflicted with a file about to be checked out
+(e.g. during linkgit:git-checkout[1] or linkgit:git-merge[1]) would be
+deleted. This could lead to loss of user data and is no longer the
+default, See `trashable` in linkgit:gitattributes[5]. for how to
+selectively enable this behavior.
+
 EXAMPLES
 --------

diff --git a/attr.c b/attr.c
index 60d284796d..930af78650 100644
--- a/attr.c
+++ b/attr.c
@@ -1186,3 +1186,12 @@ void attr_start(void)
 	pthread_mutex_init(&check_vector.mutex, NULL);
 #endif
 }
+
+int is_trashable_file(struct index_state *istate, const char *path)
+{
+	static struct attr_check *check;
+	if (!check)
+		check = attr_check_initl("trashable", NULL);
+	git_check_attr(istate, path, check);
+	return check && ATTR_TRUE(check->items[0].value);
+}
diff --git a/attr.h b/attr.h
index b0378bfe5f..ccf4d4e6b5 100644
--- a/attr.h
+++ b/attr.h
@@ -82,4 +82,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction);

 void attr_start(void);

+int is_trashable_file(struct index_state *istate, const char *path);
+
 #endif /* ATTR_H */
diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh
index 016391723c..d2ceee33d2 100755
--- a/t/lib-submodule-update.sh
+++ b/t/lib-submodule-update.sh
@@ -844,6 +844,8 @@ test_submodule_switch_recursing_with_args () {
 			git branch -t add_sub1 origin/add_sub1 &&
 			: >sub1 &&
 			echo sub1 >.git/info/exclude &&
+			test_must_fail $command add_sub1 &&
+			echo sub1 trashable >.gitattributes &&
 			$command add_sub1 &&
 			test_superproject_content origin/add_sub1 &&
 			test_submodule_content sub1 origin/add_sub1
diff --git a/t/t1004-read-tree-m-u-wf.sh b/t/t1004-read-tree-m-u-wf.sh
index c13578a635..2243cd955e 100755
--- a/t/t1004-read-tree-m-u-wf.sh
+++ b/t/t1004-read-tree-m-u-wf.sh
@@ -63,8 +63,10 @@ test_expect_success 'two-way with incorrect --exclude-per-directory (2)' '
 	fi
 '

-test_expect_success 'two-way clobbering a ignored file' '
+test_expect_success 'two-way keeping a ignored file, trashing a trashable file' '

+	read_tree_u_must_fail -m -u --exclude-per-directory=.gitignore master side &&
+	echo file2 trashable >.gitattributes &&
 	read_tree_u_must_succeed -m -u --exclude-per-directory=.gitignore master side
 '

@@ -106,7 +108,7 @@ test_expect_success 'three-way not clobbering a working tree file' '

 echo >.gitignore file3

-test_expect_success 'three-way not complaining on an untracked file' '
+test_expect_success 'three-way complaining on an untracked file, trashing a trashable file' '

 	git reset --hard &&
 	rm -f file2 subdir/file2 file3 subdir/file3 &&
@@ -114,6 +116,8 @@ test_expect_success 'three-way not complaining on an untracked file' '
 	echo >file3 file three created in master, untracked &&
 	echo >subdir/file3 file three created in master, untracked &&

+	read_tree_u_must_fail -m -u --exclude-per-directory=.gitignore branch-point master side &&
+	echo file3 trashable >.gitattributes &&
 	read_tree_u_must_succeed -m -u --exclude-per-directory=.gitignore branch-point master side
 '

diff --git a/unpack-trees.c b/unpack-trees.c
index 7570df481b..e9a7fb6583 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1895,9 +1895,10 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
 		return 0;

 	if (o->dir &&
-	    is_excluded(o->dir, o->src_index, name, &dtype))
+	    is_excluded(o->dir, o->src_index, name, &dtype) &&
+	    is_trashable_file(o->src_index, name))
 		/*
-		 * ce->name is explicitly excluded, so it is Ok to
+		 * ce->name is explicitly trashable, so it is Ok to
 		 * overwrite it.
 		 */
 		return 0;

^ permalink raw reply related	[relevance 4%]

* Re: [RFC PATCH] Introduce "precious" file concept
  @ 2018-11-11 12:33 11%   ` Ævar Arnfjörð Bjarmason
  2018-11-11 13:06  4%     ` Ævar Arnfjörð Bjarmason
                       ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-11-11 12:33 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: git, Steffen Jost, Joshua Jensen, Per Lundberg, Junio C Hamano,
	Matthieu Moy, Clemens Buchacher, Holger Hellmuth, Kevin Ballard


[CC-ing some of the people involved in recent threads about this]

On Sun, Nov 11 2018, Nguyễn Thái Ngọc Duy wrote:

> Since this topic has come up twice recently, I revisited this
> "precious" thingy that I started four years ago and tried to see if I
> could finally finish it. There are a couple things to be sorted out...
>
> A new attribute "precious" is added to indicate that certain files
> have valuable content and should not be easily discarded even if they
> are ignored or untracked (*).
>
> So far there are two parts of Git that are made aware of precious
> files: "git clean" will leave precious files alone and unpack-trees.c
> (i.e. merges and branch switches) will not overwrite
> ignored-but-precious files.
>
> Is there any other parts of Git that should be made aware of this
> "precious" attribute?
>
> Also while "precious" is a fun name, but it does not sound serious.
> Any suggestions? Perhaps "valuable"?
>
> Very lightly tested. The patch is more to have something to discuss
> than is bug free and ready to use.
>
> (*) Note that tracked files could be marked "precious" in the future
>     too although the exact semantics is not very clear since tracked
>     files are by default precious.
>
>     But something like "index log" could use this to record all
>     changes to precious files instead of just "git add -p" changes,
>     for example. So these files are in a sense more precious than
>     other tracked files.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  Documentation/git-clean.txt     |  3 ++-
>  Documentation/gitattributes.txt | 13 +++++++++++++
>  attr.c                          |  9 +++++++++
>  attr.h                          |  2 ++
>  builtin/clean.c                 | 19 ++++++++++++++++---
>  unpack-trees.c                  |  3 ++-
>  6 files changed, 44 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
> index 03056dad0d..a9beadfb12 100644
> --- a/Documentation/git-clean.txt
> +++ b/Documentation/git-clean.txt
> @@ -21,7 +21,8 @@ option is specified, ignored files are also removed. This can, for
>  example, be useful to remove all build products.
>
>  If any optional `<path>...` arguments are given, only those paths
> -are affected.
> +are affected. Ignored or untracked files with `precious` attributes
> +are not removed.
>
>  OPTIONS
>  -------
> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
> index b8392fc330..c722479bdc 100644
> --- a/Documentation/gitattributes.txt
> +++ b/Documentation/gitattributes.txt
> @@ -1188,6 +1188,19 @@ If this attribute is not set or has an invalid value, the value of the
>  (See linkgit:git-config[1]).
>
>
> +Precious files
> +~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +`precious`
> +^^^^^^^^^^
> +
> +This attribute is set on files to indicate that their content is
> +valuable. Many commands will behave slightly different on precious
> +files. linkgit:git-clean[1] will leave precious files alone. Merging
> +and branch switching will not silently overwrite ignored files that
> +are marked "precious".
> +
> +
>  USING MACRO ATTRIBUTES
>  ----------------------
>
> diff --git a/attr.c b/attr.c
> index 60d284796d..d06ca0ae4b 100644
> --- a/attr.c
> +++ b/attr.c
> @@ -1186,3 +1186,12 @@ void attr_start(void)
>  	pthread_mutex_init(&check_vector.mutex, NULL);
>  #endif
>  }
> +
> +int is_precious_file(struct index_state *istate, const char *path)
> +{
> +	static struct attr_check *check;
> +	if (!check)
> +		check = attr_check_initl("precious", NULL);
> +	git_check_attr(istate, path, check);
> +	return check && ATTR_TRUE(check->items[0].value);
> +}

If we merge two branches is this using the merged post-image of
.gitattributes as a source?

>  	if (o->dir &&
> -	    is_excluded(o->dir, o->src_index, name, &dtype))
> +	    is_excluded(o->dir, o->src_index, name, &dtype) &&
> +	    !is_precious_file(o->src_index, name))
>  		/*
>  		 * ce->name is explicitly excluded, so it is Ok to
>  		 * overwrite it.

I wonder if instead we should just be reverting c81935348b ("Fix
switching to a branch with D/F when current branch has file D.",
2007-03-15), which these days (haven't dug deeply) would just be this,
right?:

>    diff --git a/unpack-trees.c b/unpack-trees.c
    index 7570df481b..b3efaddd4f 100644
    --- a/unpack-trees.c
    +++ b/unpack-trees.c
    @@ -1894,13 +1894,6 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
     	if (ignore_case && icase_exists(o, name, len, st))
     		return 0;

    -	if (o->dir &&
    -	    is_excluded(o->dir, o->src_index, name, &dtype))
    -		/*
    -		 * ce->name is explicitly excluded, so it is Ok to
    -		 * overwrite it.
    -		 */
    -		return 0;
     	if (S_ISDIR(st->st_mode)) {
     		/*
     		 * We are checking out path "foo" and

Something like the approach you're taking will absolutely work from a
technical standpoint, but I fear that it's going to be useless in
practice.

The users who need protection against git deleting their files the most
are exactly the sort of users who aren't expert-level enough to
understand the nuances of how the semantics of .gitignore and "precious"
are going to interact before git eats their data.

This is pretty apparent from the bug reports we're getting about
this. None of them are:

    "Hey, I 100% understood .gitignore semantics including this one part
    of the docs where you say you'll do this, but just forgot one day
    and deleted my work. Can we get some more safety?"

But rather (with some hyperbole for effect):

    "ZOMG git deleted my file! Is this a bug??"

So I think we should have the inverse of this "precious"
attribute". Just a change to the docs to say that .gitignore doesn't
imply these eager deletion semantics on tree unpacking anymore, and if
users want it back they can define a "garbage" attribute
(s/precious/garbage/).

That will lose no data, and in the very rare cases where a checkout of
tracked files would overwrite an ignored pattern, we can just error out
(as we do with the "Ok to overwrite" branch removed) and tell the user
to delete the files to proceed.

Three tests in our test suite fail with that patch applied, and they're
explicitly testing for exactly the sort of scenario where users are likely to lose data. I.e.:

 1. Open a tracked file in an editor
 2. Save it
 3. Switch to a topic branch, that has different .gitignore semantics
    (e.g. let's say a build/ dir exists there)
 4. Have their work deleted

So actually in writing this out I've become convinced that this
"precious" approach can't work either, because *even if* you're an
expert who manages to perfectly define their .gitignore and "precious"
rules in advance to avoid data deletion, those rules will *also* need to
take into account switching between branches (or even different
histories) where you have other sorts of rules.

So really, if there's ambiguity let's just not delete stuff by default
and ask the user to resolve it.

^ permalink raw reply	[relevance 11%]

* Re: [RFC PATCH] Introduce "precious" file concept
  2018-11-11  9:52 20% [RFC PATCH] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
  @ 2018-11-11 12:15 11% ` Bert Wesarg
  2018-11-11 12:59 12% ` Junio C Hamano
  2018-11-26 19:38  6% ` [PATCH v2 0/2] Precios files round two Nguyễn Thái Ngọc Duy
  3 siblings, 0 replies; 200+ results
From: Bert Wesarg @ 2018-11-11 12:15 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc; +Cc: Git Mailing List

On Sun, Nov 11, 2018 at 10:53 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>
> Also while "precious" is a fun name, but it does not sound serious.
> Any suggestions? Perhaps "valuable"?

"precious" is also used by POSIX make:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html

Bert

^ permalink raw reply	[relevance 11%]

* [RFC PATCH] Introduce "precious" file concept
@ 2018-11-11  9:52 20% Nguyễn Thái Ngọc Duy
                     ` (3 more replies)
  0 siblings, 4 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-11-11  9:52 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Since this topic has come up twice recently, I revisited this
"precious" thingy that I started four years ago and tried to see if I
could finally finish it. There are a couple things to be sorted out...

A new attribute "precious" is added to indicate that certain files
have valuable content and should not be easily discarded even if they
are ignored or untracked (*).

So far there are two parts of Git that are made aware of precious
files: "git clean" will leave precious files alone and unpack-trees.c
(i.e. merges and branch switches) will not overwrite
ignored-but-precious files.

Is there any other parts of Git that should be made aware of this
"precious" attribute?

Also while "precious" is a fun name, but it does not sound serious.
Any suggestions? Perhaps "valuable"?

Very lightly tested. The patch is more to have something to discuss
than is bug free and ready to use.

(*) Note that tracked files could be marked "precious" in the future
    too although the exact semantics is not very clear since tracked
    files are by default precious.

    But something like "index log" could use this to record all
    changes to precious files instead of just "git add -p" changes,
    for example. So these files are in a sense more precious than
    other tracked files.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-clean.txt     |  3 ++-
 Documentation/gitattributes.txt | 13 +++++++++++++
 attr.c                          |  9 +++++++++
 attr.h                          |  2 ++
 builtin/clean.c                 | 19 ++++++++++++++++---
 unpack-trees.c                  |  3 ++-
 6 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt
index 03056dad0d..a9beadfb12 100644
--- a/Documentation/git-clean.txt
+++ b/Documentation/git-clean.txt
@@ -21,7 +21,8 @@ option is specified, ignored files are also removed. This can, for
 example, be useful to remove all build products.
 
 If any optional `<path>...` arguments are given, only those paths
-are affected.
+are affected. Ignored or untracked files with `precious` attributes
+are not removed.
 
 OPTIONS
 -------
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index b8392fc330..c722479bdc 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -1188,6 +1188,19 @@ If this attribute is not set or has an invalid value, the value of the
 (See linkgit:git-config[1]).
 
 
+Precious files
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+`precious`
+^^^^^^^^^^
+
+This attribute is set on files to indicate that their content is
+valuable. Many commands will behave slightly different on precious
+files. linkgit:git-clean[1] will leave precious files alone. Merging
+and branch switching will not silently overwrite ignored files that
+are marked "precious".
+
+
 USING MACRO ATTRIBUTES
 ----------------------
 
diff --git a/attr.c b/attr.c
index 60d284796d..d06ca0ae4b 100644
--- a/attr.c
+++ b/attr.c
@@ -1186,3 +1186,12 @@ void attr_start(void)
 	pthread_mutex_init(&check_vector.mutex, NULL);
 #endif
 }
+
+int is_precious_file(struct index_state *istate, const char *path)
+{
+	static struct attr_check *check;
+	if (!check)
+		check = attr_check_initl("precious", NULL);
+	git_check_attr(istate, path, check);
+	return check && ATTR_TRUE(check->items[0].value);
+}
diff --git a/attr.h b/attr.h
index b0378bfe5f..b9a9751a66 100644
--- a/attr.h
+++ b/attr.h
@@ -82,4 +82,6 @@ void git_attr_set_direction(enum git_attr_direction new_direction);
 
 void attr_start(void);
 
+int is_precious_file(struct index_state *istate, const char *path);
+
 #endif /* ATTR_H */
diff --git a/builtin/clean.c b/builtin/clean.c
index 8d9a7dc206..9e554448a6 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -17,6 +17,7 @@
 #include "color.h"
 #include "pathspec.h"
 #include "help.h"
+#include "attr.h"
 
 static int force = -1; /* unset */
 static int interactive;
@@ -30,6 +31,8 @@ static const char *const builtin_clean_usage[] = {
 
 static const char *msg_remove = N_("Removing %s\n");
 static const char *msg_would_remove = N_("Would remove %s\n");
+static const char *msg_skip_precious = N_("Skipping precious file %s\n");
+static const char *msg_would_skip_precious = N_("Would skip precious file %s\n");
 static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 static const char *msg_warn_remove_failed = N_("failed to remove %s");
@@ -152,6 +155,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 	struct dirent *e;
 	int res = 0, ret = 0, gone = 1, original_len = path->len, len;
 	struct string_list dels = STRING_LIST_INIT_DUP;
+	const char *rel_path;
 
 	*dir_gone = 1;
 
@@ -191,9 +195,15 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 
 		strbuf_setlen(path, len);
 		strbuf_addstr(path, e->d_name);
-		if (lstat(path->buf, &st))
+		if (lstat(path->buf, &st)) {
 			; /* fall thru */
-		else if (S_ISDIR(st.st_mode)) {
+		} else if ((!prefix || skip_prefix(path->buf, prefix, &rel_path)) &&
+			   is_precious_file(&the_index, rel_path)) {
+			quote_path_relative(path->buf, prefix, &quoted);
+			printf(dry_run ? _(msg_would_skip_precious) : _(msg_skip_precious), quoted.buf);
+			*dir_gone = 0;
+			continue;
+		} else if (S_ISDIR(st.st_mode)) {
 			if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
 				ret = 1;
 			if (gone) {
@@ -1017,7 +1027,10 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 		if (lstat(abs_path.buf, &st))
 			continue;
 
-		if (S_ISDIR(st.st_mode)) {
+		if (is_precious_file(&the_index, item->string)) {
+			qname = quote_path_relative(item->string, NULL, &buf);
+			printf(dry_run ? _(msg_would_skip_precious) : _(msg_skip_precious), qname);
+		} else if (S_ISDIR(st.st_mode)) {
 			if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone))
 				errors++;
 			if (gone && !quiet) {
diff --git a/unpack-trees.c b/unpack-trees.c
index 7570df481b..d49fe0f77e 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1895,7 +1895,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
 		return 0;
 
 	if (o->dir &&
-	    is_excluded(o->dir, o->src_index, name, &dtype))
+	    is_excluded(o->dir, o->src_index, name, &dtype) &&
+	    !is_precious_file(o->src_index, name))
 		/*
 		 * ce->name is explicitly excluded, so it is Ok to
 		 * overwrite it.
-- 
2.19.1.1235.ga92291acdb


^ permalink raw reply related	[relevance 20%]

* Re: Ignored files being silently overwritten when switching branches
  2018-10-16 15:05  4%         ` Duy Nguyen
@ 2018-10-18  1:55  4%           ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2018-10-18  1:55 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Ævar Arnfjörð Bjarmason, Jeff King, per.lundberg,
	Git Mailing List, git, Clemens Buchacher, Holger Hellmuth (IKS),
	Kevin Ballard

Duy Nguyen <pclouds@gmail.com> writes:

> Just fyi I also have some wip changes that add the forth "precious"
> class in addition to tracked, untracked and ignored [1]. If someone
> has time it could be another option to pick up.

It is much more sensible than gaining the ability to express
precious by trading away the ability to express expendable, I would
think.


^ permalink raw reply	[relevance 4%]

* Re: Ignored files being silently overwritten when switching branches
  2018-10-16  9:10  3%       ` Ignored files being silently overwritten when switching branches Ævar Arnfjörð Bjarmason
@ 2018-10-16 15:05  4%         ` Duy Nguyen
  2018-10-18  1:55  4%           ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Duy Nguyen @ 2018-10-16 15:05 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Jeff King, per.lundberg, Git Mailing List, Junio C Hamano, git,
	Clemens Buchacher, Holger Hellmuth (IKS), Kevin Ballard

On Tue, Oct 16, 2018 at 11:12 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
>
> On Tue, Oct 16 2018, Jeff King wrote:
>
> > On Mon, Oct 15, 2018 at 01:01:50PM +0000, Per Lundberg wrote:
> >
> >> Sorry if this question has been asked before; I skimmed through the list
> >> archives and the FAQ but couldn't immediately find it - please point me
> >> in the right direction if it has indeed been discussed before.
> >
> > It is a frequently asked question, but it doesn't seem to be in any FAQ
> > that I could find. The behavior you're seeing is intended. See this
> > message (and the rest of the thread) for discussion:
> >
> >   https://public-inbox.org/git/7viq39avay.fsf@alter.siamese.dyndns.org/
> >
> >> So my question is: is this by design or should this be considered a bug
> >> in git? Of course, it depends largely on what .gitignore is being used
> >> for - if we are talking about files which can easily be regenerated
> >> (build artifacts, node_modules folders etc.) I can totally understand
> >> the current behavior, but when dealing with more sensitive & important
> >> content it's a bit inconvenient.
> >
> > Basically: yes. It would be nice to have that "do not track this, but do
> > not trash it either" state for a file, but Git does not currently
> > support that.
>
> There's some patches in that thread that could be picked up by someone
> interested. I think the approach mentioned by Matthieu Moy here makes
> the most sense:
> https://public-inbox.org/git/vpqd3t9656k.fsf@bauges.imag.fr/
>
> I don't think the rationale mentioned by Junio in
> https://public-inbox.org/git/7v4oepaup7.fsf@alter.siamese.dyndns.org/ is
> very convincing.

Just fyi I also have some wip changes that add the forth "precious"
class in addition to tracked, untracked and ignored [1]. If someone
has time it could be another option to pick up.

[1] https://gitlab.com/pclouds/git/commit/0e7f7afa1879b055369ebd3f1224311c43c8a32b
-- 
Duy

^ permalink raw reply	[relevance 4%]

* Re: Ignored files being silently overwritten when switching branches
  @ 2018-10-16  9:10  3%       ` Ævar Arnfjörð Bjarmason
  2018-10-16 15:05  4%         ` Duy Nguyen
  0 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2018-10-16  9:10 UTC (permalink / raw)
  To: Jeff King
  Cc: Per Lundberg, git@vger.kernel.org, Junio C Hamano, Matthieu Moy,
	Clemens Buchacher, Holger Hellmuth, Kevin Ballard


On Tue, Oct 16 2018, Jeff King wrote:

> On Mon, Oct 15, 2018 at 01:01:50PM +0000, Per Lundberg wrote:
>
>> Sorry if this question has been asked before; I skimmed through the list
>> archives and the FAQ but couldn't immediately find it - please point me
>> in the right direction if it has indeed been discussed before.
>
> It is a frequently asked question, but it doesn't seem to be in any FAQ
> that I could find. The behavior you're seeing is intended. See this
> message (and the rest of the thread) for discussion:
>
>   https://public-inbox.org/git/7viq39avay.fsf@alter.siamese.dyndns.org/
>
>> So my question is: is this by design or should this be considered a bug
>> in git? Of course, it depends largely on what .gitignore is being used
>> for - if we are talking about files which can easily be regenerated
>> (build artifacts, node_modules folders etc.) I can totally understand
>> the current behavior, but when dealing with more sensitive & important
>> content it's a bit inconvenient.
>
> Basically: yes. It would be nice to have that "do not track this, but do
> not trash it either" state for a file, but Git does not currently
> support that.

There's some patches in that thread that could be picked up by someone
interested. I think the approach mentioned by Matthieu Moy here makes
the most sense:
https://public-inbox.org/git/vpqd3t9656k.fsf@bauges.imag.fr/

I don't think the rationale mentioned by Junio in
https://public-inbox.org/git/7v4oepaup7.fsf@alter.siamese.dyndns.org/ is
very convincing.

The question is not whether .gitignore is intended to be used in some
specific way, e.g. only ignoring *.o files, but whether we can
reasonably suspect that users use the combination of the features we
expose in such a way that their precious data gets destroyed. User data
should get the benefit of the doubt.

Off the top of my head, I can imagine many ways in which this'll go
wrong:

 1. Even if you're using .gitignore only for "trashable" as as Junio
    mentions, git not trashing your data depends on everyone who
    modifies .gitignore in your project having enough situational
    awareness not to inadvertently add a glob to the file which
    *accidentally* ignores existing files, and *nothing warns about
    this*.

    Between the caveat noted in "It is not possible to re-include[...]"
    in gitignore(5) and negative pathspecs it can be really easy to get
    this wrong.

    So e.g. in git.git I can add a line with "*" to .gitignore, and
    nothing will complain or look unusual as long as I'm not introducing
    new files, and I'll only find out when some-new-file.c of mine gets
    trashed.

 2. Related, the UI "git add <ignored>" presents is just "Use -f if you
    really want to add them". Users who aren't careful will just think
    "oh, I just need -f in this case" and not alter .gitignore, leaving
    a timebomb for future users.

    Those new users will have no way of knowing that they've cloned a
    repo with a broken overzealous .gitignore, e.g. there's nothing on
    clone that says "you've just cloned a repo with N files, all of
    which are ignored, so git clean etc. will likely wipe out anything
    you have in the checkout".

 3. Since we implictly expose this "you need a one-off action to
    override .gitignore" noted in #2 users can and *do* use this for
    "soft" ignores.

    E.g. in a big work repo there's an ignore for *.png, even though the
    repo has thousands of such files, because it's not considered good
    practice to add them anymore (there's another static repo), and
    someone thought to use .gitignore to enforce that suggestion.

    I have a personal repo where I only want *.gpg files, and due to the
    inability to re-include files recursively (noted in #1) I just
    ignore '*' and use git veeery carefully. I was only worried about
    'git clean' so far, but now I see I need to worry about "checkout"
    as well.

But maybe the use-cases I'm mentioning are highly unusual and the repos
at work have ended up in some bizarre state and nobody else cares about
this.

It would be interesting if someone at a big git hosting providers (hint:
Jeff :) could provide some numbers about how common it is to have a
repository containing tracked files ignored by a .gitignore the
repository itself carries. This wouldn't cover all of #1-3 above, but is
probably a pretty good proxy metric.

I thought this could be done by:

    git ls-tree -r --name-only HEAD  | git check-ignore --no-index --stdin

But I see that e.g. on git.git this goes wrong due to
t/helper/.gitignore. So I don't know how one would answer "does this
repo have .gitignored files tracked?" in a one-liner.

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] range-diff: allow to diff files regardless submodule
  @ 2018-10-12  9:24  4%     ` Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2018-10-12  9:24 UTC (permalink / raw)
  To: Lucas De Marchi
  Cc: sandals, Lucas De Marchi, git, t.gummerer, sunshine, gitster



On Thu, 11 Oct 2018, Lucas De Marchi wrote:

> On Wed, Oct 10, 2018 at 5:02 PM brian m. carlson
> <sandals@crustytoothpaste.net> wrote:
> >
> > On Wed, Oct 10, 2018 at 08:09:16AM -0700, Lucas De Marchi wrote:
> > > Do like it's done in grep so mode doesn't end up as
> > > 0160000, which means range-diff doesn't work if one has
> > > "submodule.diff = log" in the configuration. Without this
> > > while using range-diff I only get a
> > >
> > >     Submodule a 0000000...0000000 (new submodule)
> > >
> > > instead of the diff between the revisions.
> > >
> > > Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> > > ---
> > >  range-diff.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/range-diff.c b/range-diff.c
> > > index 60edb2f518..bd8083f2d1 100644
> > > --- a/range-diff.c
> > > +++ b/range-diff.c
> > > @@ -354,7 +354,7 @@ static struct diff_filespec *get_filespec(const char *name, const char *p)
> > >  {
> > >       struct diff_filespec *spec = alloc_filespec(name);
> > >
> > > -     fill_filespec(spec, &null_oid, 0, 0644);
> > > +     fill_filespec(spec, &null_oid, 0, 0100644);
> >
> > If we have a system that has different mode values from the common Unix
> > ones, is this still correct or does it need to change?
> 
> From what I can see this would still be correct, or at least git-grep
> implementation would be broken.

As you can see from the Windows port: we are stuck with the simplistic
POSIX permissions in Git, and platforms that have a different permission
system have to emulate it.

We only use preciously few bit masks, anyway. For example, we do not
really use the lower 12 bits for anything but "executable or not?"

So Lucas' patch is correct, AFAICT.

Ciao,
Dscho

> 
> Lucas De Marchi
> > --
> > brian m. carlson: Houston, Texas, US
> > OpenPGP: https://keybase.io/bk2204
> 
> 
> 
> -- 
> Lucas De Marchi
> 

^ permalink raw reply	[relevance 4%]

* [PATCH v5 13/23] merge.c: remove implicit dependency on the_index
  @ 2018-09-21 15:57  4%         ` Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-09-21 15:57 UTC (permalink / raw)
  To: pclouds; +Cc: git, gitster, sbeller

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/merge.c |  8 +++++---
 builtin/pull.c  |  7 +++++--
 cache.h         |  6 ++++--
 merge.c         | 20 +++++++++++---------
 sequencer.c     |  6 +++---
 5 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 592cb19caf..5f79fc5fd7 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -728,8 +728,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 			die(_("unable to write %s"), get_index_file());
 		return clean ? 0 : 1;
 	} else {
-		return try_merge_command(strategy, xopts_nr, xopts,
-						common, head_arg, remoteheads);
+		return try_merge_command(the_repository,
+					 strategy, xopts_nr, xopts,
+					 common, head_arg, remoteheads);
 	}
 }
 
@@ -1470,7 +1471,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(&head_commit->object.oid,
+		if (checkout_fast_forward(the_repository,
+					  &head_commit->object.oid,
 					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..33b7100837 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -562,7 +562,9 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
+	if (checkout_fast_forward(the_repository,
+				  the_hash_algo->empty_tree,
+				  merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -915,7 +917,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(&orig_head, &curr_head, 0))
+		if (checkout_fast_forward(the_repository, &orig_head,
+					  &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index 260e4ee44a..49fe83331c 100644
--- a/cache.h
+++ b/cache.h
@@ -1716,10 +1716,12 @@ extern struct startup_info *startup_info;
 
 /* merge.c */
 struct commit_list;
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const struct object_id *from,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *from,
 			  const struct object_id *to,
 			  int overwrite_ignore);
 
diff --git a/merge.c b/merge.c
index e30e03fb84..91008f7602 100644
--- a/merge.c
+++ b/merge.c
@@ -14,7 +14,8 @@ static const char *merge_argument(struct commit *commit)
 	return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
 }
 
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		      const char *strategy, size_t xopts_nr,
 		      const char **xopts, struct commit_list *common,
 		      const char *head_arg, struct commit_list *remotes)
 {
@@ -35,15 +36,16 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
 	argv_array_clear(&args);
 
-	discard_cache();
-	if (read_cache() < 0)
+	discard_index(r->index);
+	if (read_index(r->index) < 0)
 		die(_("failed to read the cache"));
-	resolve_undo_clear();
+	resolve_undo_clear_index(r->index);
 
 	return ret;
 }
 
-int checkout_fast_forward(const struct object_id *head,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *head,
 			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
@@ -54,7 +56,7 @@ int checkout_fast_forward(const struct object_id *head,
 	struct dir_struct dir;
 	struct lock_file lock_file = LOCK_INIT;
 
-	refresh_cache(REFRESH_QUIET);
+	refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
 
 	if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
@@ -86,8 +88,8 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 
 	opts.head_idx = 1;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
+	opts.src_index = r->index;
+	opts.dst_index = r->index;
 	opts.update = 1;
 	opts.verbose_update = 1;
 	opts.merge = 1;
@@ -101,7 +103,7 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 	clear_unpack_trees_porcelain(&opts);
 
-	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+	if (write_locked_index(r->index, &lock_file, COMMIT_LOCK))
 		return error(_("unable to write new index file"));
 	return 0;
 }
diff --git a/sequencer.c b/sequencer.c
index dc2c58d464..2adc66f45e 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -470,8 +470,8 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf sb = STRBUF_INIT;
 	struct strbuf err = STRBUF_INIT;
 
-	read_cache();
-	if (checkout_fast_forward(from, to, 1))
+	read_index(&the_index);
+	if (checkout_fast_forward(the_repository, from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
@@ -1827,7 +1827,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 
 		commit_list_insert(base, &common);
 		commit_list_insert(next, &remotes);
-		res |= try_merge_command(opts->strategy,
+		res |= try_merge_command(the_repository, opts->strategy,
 					 opts->xopts_nr, (const char **)opts->xopts,
 					common, oid_to_hex(&head), remotes);
 		free_commit_list(common);
-- 
2.19.0.640.gcd3aa10a8a


^ permalink raw reply related	[relevance 4%]

* [PATCH v4 13/23] merge.c: remove implicit dependency on the_index
  @ 2018-09-15 16:17  4%       ` Nguyễn Thái Ngọc Duy
    1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-09-15 16:17 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Stefan Beller,
	Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/merge.c |  8 +++++---
 builtin/pull.c  |  7 +++++--
 cache.h         |  6 ++++--
 merge.c         | 20 +++++++++++---------
 sequencer.c     |  6 +++---
 5 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 592cb19caf..5f79fc5fd7 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -728,8 +728,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 			die(_("unable to write %s"), get_index_file());
 		return clean ? 0 : 1;
 	} else {
-		return try_merge_command(strategy, xopts_nr, xopts,
-						common, head_arg, remoteheads);
+		return try_merge_command(the_repository,
+					 strategy, xopts_nr, xopts,
+					 common, head_arg, remoteheads);
 	}
 }
 
@@ -1470,7 +1471,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(&head_commit->object.oid,
+		if (checkout_fast_forward(the_repository,
+					  &head_commit->object.oid,
 					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..33b7100837 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -562,7 +562,9 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
+	if (checkout_fast_forward(the_repository,
+				  the_hash_algo->empty_tree,
+				  merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -915,7 +917,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(&orig_head, &curr_head, 0))
+		if (checkout_fast_forward(the_repository, &orig_head,
+					  &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index 260e4ee44a..49fe83331c 100644
--- a/cache.h
+++ b/cache.h
@@ -1716,10 +1716,12 @@ extern struct startup_info *startup_info;
 
 /* merge.c */
 struct commit_list;
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const struct object_id *from,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *from,
 			  const struct object_id *to,
 			  int overwrite_ignore);
 
diff --git a/merge.c b/merge.c
index e30e03fb84..91008f7602 100644
--- a/merge.c
+++ b/merge.c
@@ -14,7 +14,8 @@ static const char *merge_argument(struct commit *commit)
 	return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
 }
 
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		      const char *strategy, size_t xopts_nr,
 		      const char **xopts, struct commit_list *common,
 		      const char *head_arg, struct commit_list *remotes)
 {
@@ -35,15 +36,16 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
 	argv_array_clear(&args);
 
-	discard_cache();
-	if (read_cache() < 0)
+	discard_index(r->index);
+	if (read_index(r->index) < 0)
 		die(_("failed to read the cache"));
-	resolve_undo_clear();
+	resolve_undo_clear_index(r->index);
 
 	return ret;
 }
 
-int checkout_fast_forward(const struct object_id *head,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *head,
 			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
@@ -54,7 +56,7 @@ int checkout_fast_forward(const struct object_id *head,
 	struct dir_struct dir;
 	struct lock_file lock_file = LOCK_INIT;
 
-	refresh_cache(REFRESH_QUIET);
+	refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
 
 	if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
@@ -86,8 +88,8 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 
 	opts.head_idx = 1;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
+	opts.src_index = r->index;
+	opts.dst_index = r->index;
 	opts.update = 1;
 	opts.verbose_update = 1;
 	opts.merge = 1;
@@ -101,7 +103,7 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 	clear_unpack_trees_porcelain(&opts);
 
-	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+	if (write_locked_index(r->index, &lock_file, COMMIT_LOCK))
 		return error(_("unable to write new index file"));
 	return 0;
 }
diff --git a/sequencer.c b/sequencer.c
index 84bf598c3e..47d0e7b0bd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -470,8 +470,8 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf sb = STRBUF_INIT;
 	struct strbuf err = STRBUF_INIT;
 
-	read_cache();
-	if (checkout_fast_forward(from, to, 1))
+	read_index(&the_index);
+	if (checkout_fast_forward(the_repository, from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
@@ -1798,7 +1798,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 
 		commit_list_insert(base, &common);
 		commit_list_insert(next, &remotes);
-		res |= try_merge_command(opts->strategy,
+		res |= try_merge_command(the_repository, opts->strategy,
 					 opts->xopts_nr, (const char **)opts->xopts,
 					common, oid_to_hex(&head), remotes);
 		free_commit_list(common);
-- 
2.19.0.rc0.337.ge906d732e7


^ permalink raw reply related	[relevance 4%]

* [PATCH v3 13/23] merge.c: remove implicit dependency on the_index
  @ 2018-09-09  8:54  4%     ` Nguyễn Thái Ngọc Duy
    1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-09-09  8:54 UTC (permalink / raw)
  To: pclouds; +Cc: git, sbeller, Junio C Hamano

---
 builtin/merge.c |  8 +++++---
 builtin/pull.c  |  7 +++++--
 cache.h         |  6 ++++--
 merge.c         | 20 +++++++++++---------
 sequencer.c     |  6 +++---
 5 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 592cb19caf..5f79fc5fd7 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -728,8 +728,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 			die(_("unable to write %s"), get_index_file());
 		return clean ? 0 : 1;
 	} else {
-		return try_merge_command(strategy, xopts_nr, xopts,
-						common, head_arg, remoteheads);
+		return try_merge_command(the_repository,
+					 strategy, xopts_nr, xopts,
+					 common, head_arg, remoteheads);
 	}
 }
 
@@ -1470,7 +1471,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(&head_commit->object.oid,
+		if (checkout_fast_forward(the_repository,
+					  &head_commit->object.oid,
 					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..33b7100837 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -562,7 +562,9 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
+	if (checkout_fast_forward(the_repository,
+				  the_hash_algo->empty_tree,
+				  merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -915,7 +917,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(&orig_head, &curr_head, 0))
+		if (checkout_fast_forward(the_repository, &orig_head,
+					  &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index 260e4ee44a..49fe83331c 100644
--- a/cache.h
+++ b/cache.h
@@ -1716,10 +1716,12 @@ extern struct startup_info *startup_info;
 
 /* merge.c */
 struct commit_list;
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const struct object_id *from,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *from,
 			  const struct object_id *to,
 			  int overwrite_ignore);
 
diff --git a/merge.c b/merge.c
index e30e03fb84..91008f7602 100644
--- a/merge.c
+++ b/merge.c
@@ -14,7 +14,8 @@ static const char *merge_argument(struct commit *commit)
 	return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
 }
 
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		      const char *strategy, size_t xopts_nr,
 		      const char **xopts, struct commit_list *common,
 		      const char *head_arg, struct commit_list *remotes)
 {
@@ -35,15 +36,16 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
 	argv_array_clear(&args);
 
-	discard_cache();
-	if (read_cache() < 0)
+	discard_index(r->index);
+	if (read_index(r->index) < 0)
 		die(_("failed to read the cache"));
-	resolve_undo_clear();
+	resolve_undo_clear_index(r->index);
 
 	return ret;
 }
 
-int checkout_fast_forward(const struct object_id *head,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *head,
 			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
@@ -54,7 +56,7 @@ int checkout_fast_forward(const struct object_id *head,
 	struct dir_struct dir;
 	struct lock_file lock_file = LOCK_INIT;
 
-	refresh_cache(REFRESH_QUIET);
+	refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
 
 	if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
@@ -86,8 +88,8 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 
 	opts.head_idx = 1;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
+	opts.src_index = r->index;
+	opts.dst_index = r->index;
 	opts.update = 1;
 	opts.verbose_update = 1;
 	opts.merge = 1;
@@ -101,7 +103,7 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 	clear_unpack_trees_porcelain(&opts);
 
-	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+	if (write_locked_index(r->index, &lock_file, COMMIT_LOCK))
 		return error(_("unable to write new index file"));
 	return 0;
 }
diff --git a/sequencer.c b/sequencer.c
index 84bf598c3e..47d0e7b0bd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -470,8 +470,8 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf sb = STRBUF_INIT;
 	struct strbuf err = STRBUF_INIT;
 
-	read_cache();
-	if (checkout_fast_forward(from, to, 1))
+	read_index(&the_index);
+	if (checkout_fast_forward(the_repository, from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
@@ -1798,7 +1798,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 
 		commit_list_insert(base, &common);
 		commit_list_insert(next, &remotes);
-		res |= try_merge_command(opts->strategy,
+		res |= try_merge_command(the_repository, opts->strategy,
 					 opts->xopts_nr, (const char **)opts->xopts,
 					common, oid_to_hex(&head), remotes);
 		free_commit_list(common);
-- 
2.19.0.rc0.337.ge906d732e7


^ permalink raw reply related	[relevance 4%]

* [PATCH v2 13/24] merge.c: remove implicit dependency on the_index
  @ 2018-09-03 18:09  4%   ` Nguyễn Thái Ngọc Duy
    1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-09-03 18:09 UTC (permalink / raw)
  To: pclouds; +Cc: git, Stefan Beller

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/merge.c |  8 +++++---
 builtin/pull.c  |  7 +++++--
 cache.h         |  6 ++++--
 merge.c         | 20 +++++++++++---------
 sequencer.c     |  6 +++---
 5 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 0a37d5ef2c..a56754db5c 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -728,8 +728,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 			die(_("unable to write %s"), get_index_file());
 		return clean ? 0 : 1;
 	} else {
-		return try_merge_command(strategy, xopts_nr, xopts,
-						common, head_arg, remoteheads);
+		return try_merge_command(the_repository,
+					 strategy, xopts_nr, xopts,
+					 common, head_arg, remoteheads);
 	}
 }
 
@@ -1470,7 +1471,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(&head_commit->object.oid,
+		if (checkout_fast_forward(the_repository,
+					  &head_commit->object.oid,
 					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
diff --git a/builtin/pull.c b/builtin/pull.c
index 681c127a07..33b7100837 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -562,7 +562,9 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
+	if (checkout_fast_forward(the_repository,
+				  the_hash_algo->empty_tree,
+				  merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -915,7 +917,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(&orig_head, &curr_head, 0))
+		if (checkout_fast_forward(the_repository, &orig_head,
+					  &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index 260e4ee44a..49fe83331c 100644
--- a/cache.h
+++ b/cache.h
@@ -1716,10 +1716,12 @@ extern struct startup_info *startup_info;
 
 /* merge.c */
 struct commit_list;
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const struct object_id *from,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *from,
 			  const struct object_id *to,
 			  int overwrite_ignore);
 
diff --git a/merge.c b/merge.c
index e30e03fb84..91008f7602 100644
--- a/merge.c
+++ b/merge.c
@@ -14,7 +14,8 @@ static const char *merge_argument(struct commit *commit)
 	return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
 }
 
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *r,
+		      const char *strategy, size_t xopts_nr,
 		      const char **xopts, struct commit_list *common,
 		      const char *head_arg, struct commit_list *remotes)
 {
@@ -35,15 +36,16 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
 	argv_array_clear(&args);
 
-	discard_cache();
-	if (read_cache() < 0)
+	discard_index(r->index);
+	if (read_index(r->index) < 0)
 		die(_("failed to read the cache"));
-	resolve_undo_clear();
+	resolve_undo_clear_index(r->index);
 
 	return ret;
 }
 
-int checkout_fast_forward(const struct object_id *head,
+int checkout_fast_forward(struct repository *r,
+			  const struct object_id *head,
 			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
@@ -54,7 +56,7 @@ int checkout_fast_forward(const struct object_id *head,
 	struct dir_struct dir;
 	struct lock_file lock_file = LOCK_INIT;
 
-	refresh_cache(REFRESH_QUIET);
+	refresh_index(r->index, REFRESH_QUIET, NULL, NULL, NULL);
 
 	if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
@@ -86,8 +88,8 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 
 	opts.head_idx = 1;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
+	opts.src_index = r->index;
+	opts.dst_index = r->index;
 	opts.update = 1;
 	opts.verbose_update = 1;
 	opts.merge = 1;
@@ -101,7 +103,7 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 	clear_unpack_trees_porcelain(&opts);
 
-	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+	if (write_locked_index(r->index, &lock_file, COMMIT_LOCK))
 		return error(_("unable to write new index file"));
 	return 0;
 }
diff --git a/sequencer.c b/sequencer.c
index 84bf598c3e..47d0e7b0bd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -470,8 +470,8 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf sb = STRBUF_INIT;
 	struct strbuf err = STRBUF_INIT;
 
-	read_cache();
-	if (checkout_fast_forward(from, to, 1))
+	read_index(&the_index);
+	if (checkout_fast_forward(the_repository, from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
@@ -1798,7 +1798,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 
 		commit_list_insert(base, &common);
 		commit_list_insert(next, &remotes);
-		res |= try_merge_command(opts->strategy,
+		res |= try_merge_command(the_repository, opts->strategy,
 					 opts->xopts_nr, (const char **)opts->xopts,
 					common, oid_to_hex(&head), remotes);
 		free_commit_list(common);
-- 
2.19.0.rc0.337.ge906d732e7


^ permalink raw reply related	[relevance 4%]

* [PATCH 11/21] merge.c: remove implicit dependency on the_index
  @ 2018-08-26 10:03  4% ` Nguyễn Thái Ngọc Duy
    1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-08-26 10:03 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/merge.c |  8 +++++---
 builtin/pull.c  |  7 +++++--
 cache.h         |  6 ++++--
 merge.c         | 20 +++++++++++---------
 sequencer.c     |  6 +++---
 5 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 0a37d5ef2c..a56754db5c 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -728,8 +728,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 			die(_("unable to write %s"), get_index_file());
 		return clean ? 0 : 1;
 	} else {
-		return try_merge_command(strategy, xopts_nr, xopts,
-						common, head_arg, remoteheads);
+		return try_merge_command(the_repository,
+					 strategy, xopts_nr, xopts,
+					 common, head_arg, remoteheads);
 	}
 }
 
@@ -1470,7 +1471,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(&head_commit->object.oid,
+		if (checkout_fast_forward(the_repository,
+					  &head_commit->object.oid,
 					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
diff --git a/builtin/pull.c b/builtin/pull.c
index 53bc5facfd..9b2f76f9d9 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -562,7 +562,9 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(the_hash_algo->empty_tree, merge_head, 0))
+	if (checkout_fast_forward(the_repository,
+				  the_hash_algo->empty_tree,
+				  merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -915,7 +917,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(&orig_head, &curr_head, 0))
+		if (checkout_fast_forward(the_repository, &orig_head,
+					  &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index 31013ce8af..218edaa198 100644
--- a/cache.h
+++ b/cache.h
@@ -1706,10 +1706,12 @@ extern struct startup_info *startup_info;
 
 /* merge.c */
 struct commit_list;
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *repo,
+		const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const struct object_id *from,
+int checkout_fast_forward(struct repository *repo,
+			  const struct object_id *from,
 			  const struct object_id *to,
 			  int overwrite_ignore);
 
diff --git a/merge.c b/merge.c
index e30e03fb84..3c8c769e50 100644
--- a/merge.c
+++ b/merge.c
@@ -14,7 +14,8 @@ static const char *merge_argument(struct commit *commit)
 	return oid_to_hex(commit ? &commit->object.oid : the_hash_algo->empty_tree);
 }
 
-int try_merge_command(const char *strategy, size_t xopts_nr,
+int try_merge_command(struct repository *repo,
+		      const char *strategy, size_t xopts_nr,
 		      const char **xopts, struct commit_list *common,
 		      const char *head_arg, struct commit_list *remotes)
 {
@@ -35,15 +36,16 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	ret = run_command_v_opt(args.argv, RUN_GIT_CMD);
 	argv_array_clear(&args);
 
-	discard_cache();
-	if (read_cache() < 0)
+	discard_index(repo->index);
+	if (read_index(repo->index) < 0)
 		die(_("failed to read the cache"));
-	resolve_undo_clear();
+	resolve_undo_clear_index(repo->index);
 
 	return ret;
 }
 
-int checkout_fast_forward(const struct object_id *head,
+int checkout_fast_forward(struct repository *repo,
+			  const struct object_id *head,
 			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
@@ -54,7 +56,7 @@ int checkout_fast_forward(const struct object_id *head,
 	struct dir_struct dir;
 	struct lock_file lock_file = LOCK_INIT;
 
-	refresh_cache(REFRESH_QUIET);
+	refresh_index(repo->index, REFRESH_QUIET, NULL, NULL, NULL);
 
 	if (hold_locked_index(&lock_file, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
@@ -86,8 +88,8 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 
 	opts.head_idx = 1;
-	opts.src_index = &the_index;
-	opts.dst_index = &the_index;
+	opts.src_index = repo->index;
+	opts.dst_index = repo->index;
 	opts.update = 1;
 	opts.verbose_update = 1;
 	opts.merge = 1;
@@ -101,7 +103,7 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 	clear_unpack_trees_porcelain(&opts);
 
-	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
+	if (write_locked_index(repo->index, &lock_file, COMMIT_LOCK))
 		return error(_("unable to write new index file"));
 	return 0;
 }
diff --git a/sequencer.c b/sequencer.c
index 65d371c746..83c1f0e42b 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -470,8 +470,8 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf sb = STRBUF_INIT;
 	struct strbuf err = STRBUF_INIT;
 
-	read_cache();
-	if (checkout_fast_forward(from, to, 1))
+	read_index(&the_index);
+	if (checkout_fast_forward(the_repository, from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));
@@ -1798,7 +1798,7 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
 
 		commit_list_insert(base, &common);
 		commit_list_insert(next, &remotes);
-		res |= try_merge_command(opts->strategy,
+		res |= try_merge_command(the_repository, opts->strategy,
 					 opts->xopts_nr, (const char **)opts->xopts,
 					common, oid_to_hex(&head), remotes);
 		free_commit_list(common);
-- 
2.19.0.rc0.337.ge906d732e7


^ permalink raw reply related	[relevance 4%]

* [RFC/PATCH] drop vcs-svn experiment
@ 2018-08-17 19:03  1% Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2018-08-17 19:03 UTC (permalink / raw)
  To: git; +Cc: Jonathan Nieder

The code in vcs-svn was started in 2010 as an attempt to
build a remote-helper for interacting with svn repositories
(as opposed to git-svn). However, we never got as far as
shipping a mature remote helper, and the last substantive
commit was e99d012a6bc in 2012.

We do have a git-remote-testsvn, and it is even installed as
part of "make install". But given the name, it seems
unlikely to be used by anybody (you'd have to explicitly
"git clone testsvn::$url", and there have been zero mentions
of that on the mailing list since 2013, and even that
includes the phrase "you might need to hack a bit to get it
working properly"[1]).

We also ship contrib/svn-fe, which builds on the vcs-svn
work. However, it does not seem to build out of the box for
me, as the link step misses some required libraries for
using libgit.a. Curiously, the original build breakage
bisects for me to eff80a9fd9 (Allow custom "comment char",
2013-01-16), which seems unrelated. There was an attempt to
fix it in da011cb0e7 (contrib/svn-fe: fix Makefile,
2014-08-28), but on my system that only switches the error
message.

So it seems like the result is not really usable by anybody
in practice. It would be wonderful if somebody wanted to
pick up the topic again, and potentially it's worth carrying
around for that reason. But the flip side is that people
doing a tree-wide operations have to deal with this code.
And you can see the list with (replace "HEAD" with this
commit as appropriate):

  {
    echo "--"
    git diff-tree --diff-filter=D -r --name-only HEAD^ HEAD
  } |
  git log e99d012a6bc.. --stdin

which shows 58 times somebody had to deal with the code,
generally due to a compile or test failure, or a tree-wide
style fix or API change. Let's drop it and let anybody who
wants to pick it up do so by resurrecting it from the git
history.

[1] https://public-inbox.org/git/CALkWK0mPHzKfzFKKpZkfAus3YVC9NFYDbFnt+5JQYVKipk3bQQ@mail.gmail.com/

Signed-off-by: Jeff King <peff@peff.net>
---
Of course, I could be completely wrong about people using this. Maybe
svn-fe builds are just completely broken on my system, and maybe people
really do use testsvn::. But if so, they certainly aren't talking about
it on the mailing list. :)

I'm cc-ing Jonathan as the only currently-active developer who seems to
have put significant work into this code. Maybe you have a more informed
opinion.

 .gitignore                     |   1 -
 Makefile                       |  22 --
 contrib/svn-fe/.gitignore      |   4 -
 contrib/svn-fe/Makefile        | 105 -------
 contrib/svn-fe/svn-fe.c        |  18 --
 contrib/svn-fe/svn-fe.txt      |  71 -----
 contrib/svn-fe/svnrdump_sim.py |  68 -----
 remote-testsvn.c               | 337 --------------------
 t/helper/test-line-buffer.c    |  81 -----
 t/helper/test-svn-fe.c         |  52 ----
 t/t9020-remote-svn.sh          |  89 ------
 vcs-svn/LICENSE                |  32 --
 vcs-svn/fast_export.c          | 365 ----------------------
 vcs-svn/fast_export.h          |  34 ---
 vcs-svn/line_buffer.c          | 126 --------
 vcs-svn/line_buffer.h          |  30 --
 vcs-svn/line_buffer.txt        |  77 -----
 vcs-svn/sliding_window.c       |  79 -----
 vcs-svn/sliding_window.h       |  18 --
 vcs-svn/svndiff.c              | 309 -------------------
 vcs-svn/svndiff.h              |  10 -
 vcs-svn/svndump.c              | 540 ---------------------------------
 vcs-svn/svndump.h              |  10 -
 23 files changed, 2478 deletions(-)
 delete mode 100644 contrib/svn-fe/.gitignore
 delete mode 100644 contrib/svn-fe/Makefile
 delete mode 100644 contrib/svn-fe/svn-fe.c
 delete mode 100644 contrib/svn-fe/svn-fe.txt
 delete mode 100755 contrib/svn-fe/svnrdump_sim.py
 delete mode 100644 remote-testsvn.c
 delete mode 100644 t/helper/test-line-buffer.c
 delete mode 100644 t/helper/test-svn-fe.c
 delete mode 100755 t/t9020-remote-svn.sh
 delete mode 100644 vcs-svn/LICENSE
 delete mode 100644 vcs-svn/fast_export.c
 delete mode 100644 vcs-svn/fast_export.h
 delete mode 100644 vcs-svn/line_buffer.c
 delete mode 100644 vcs-svn/line_buffer.h
 delete mode 100644 vcs-svn/line_buffer.txt
 delete mode 100644 vcs-svn/sliding_window.c
 delete mode 100644 vcs-svn/sliding_window.h
 delete mode 100644 vcs-svn/svndiff.c
 delete mode 100644 vcs-svn/svndiff.h
 delete mode 100644 vcs-svn/svndump.c
 delete mode 100644 vcs-svn/svndump.h

diff --git a/.gitignore b/.gitignore
index 3524803da5..fe022dbeb0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -131,7 +131,6 @@
 /git-remote-ext
 /git-remote-testgit
 /git-remote-testpy
-/git-remote-testsvn
 /git-repack
 /git-replace
 /git-request-pull
diff --git a/Makefile b/Makefile
index e3364a42a5..8a890e28e9 100644
--- a/Makefile
+++ b/Makefile
@@ -695,7 +695,6 @@ PROGRAM_OBJS += http-backend.o
 PROGRAM_OBJS += imap-send.o
 PROGRAM_OBJS += sh-i18n--envsubst.o
 PROGRAM_OBJS += shell.o
-PROGRAM_OBJS += remote-testsvn.o
 
 # Binary suffix, set to .exe for Windows builds
 X =
@@ -743,10 +742,8 @@ TEST_BUILTINS_OBJS += test-write-cache.o
 TEST_PROGRAMS_NEED_X += test-dump-fsmonitor
 TEST_PROGRAMS_NEED_X += test-dump-untracked-cache
 TEST_PROGRAMS_NEED_X += test-fake-ssh
-TEST_PROGRAMS_NEED_X += test-line-buffer
 TEST_PROGRAMS_NEED_X += test-parse-options
 TEST_PROGRAMS_NEED_X += test-pkt-line
-TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-tool
 
 TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
@@ -800,7 +797,6 @@ TEST_SHELL_PATH = $(SHELL_PATH)
 
 LIB_FILE = libgit.a
 XDIFF_LIB = xdiff/lib.a
-VCSSVN_LIB = vcs-svn/lib.a
 
 GENERATED_H += command-list.h
 
@@ -2229,16 +2225,9 @@ XDIFF_OBJS += xdiff/xmerge.o
 XDIFF_OBJS += xdiff/xpatience.o
 XDIFF_OBJS += xdiff/xhistogram.o
 
-VCSSVN_OBJS += vcs-svn/line_buffer.o
-VCSSVN_OBJS += vcs-svn/sliding_window.o
-VCSSVN_OBJS += vcs-svn/fast_export.o
-VCSSVN_OBJS += vcs-svn/svndiff.o
-VCSSVN_OBJS += vcs-svn/svndump.o
-
 TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
-	$(VCSSVN_OBJS) \
 	common-main.o \
 	git.o
 ifndef NO_CURL
@@ -2352,10 +2341,6 @@ git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
-git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
-	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
-	$(VCSSVN_LIB)
-
 $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
 	$(QUIET_LNCP)$(RM) $@ && \
 	ln $< $@ 2>/dev/null || \
@@ -2372,9 +2357,6 @@ $(LIB_FILE): $(LIB_OBJS)
 $(XDIFF_LIB): $(XDIFF_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
 
-$(VCSSVN_LIB): $(VCSSVN_OBJS)
-	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
-
 export DEFAULT_EDITOR DEFAULT_PAGER
 
 .PHONY: doc man man-perl html info pdf
@@ -2642,10 +2624,6 @@ perf: all
 
 .PHONY: test perf
 
-t/helper/test-line-buffer$X: $(VCSSVN_LIB)
-
-t/helper/test-svn-fe$X: $(VCSSVN_LIB)
-
 .PRECIOUS: $(TEST_OBJS)
 
 t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
diff --git a/contrib/svn-fe/.gitignore b/contrib/svn-fe/.gitignore
deleted file mode 100644
index 02a7791585..0000000000
--- a/contrib/svn-fe/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/*.xml
-/*.1
-/*.html
-/svn-fe
diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
deleted file mode 100644
index e8651aaf4b..0000000000
--- a/contrib/svn-fe/Makefile
+++ /dev/null
@@ -1,105 +0,0 @@
-all:: svn-fe$X
-
-CC = cc
-RM = rm -f
-MV = mv
-
-CFLAGS = -g -O2 -Wall
-LDFLAGS =
-EXTLIBS = -lz
-
-include ../../config.mak.uname
--include ../../config.mak.autogen
--include ../../config.mak
-
-ifeq ($(uname_S),Darwin)
-	ifndef NO_FINK
-		ifeq ($(shell test -d /sw/lib && echo y),y)
-			CFLAGS += -I/sw/include
-			LDFLAGS += -L/sw/lib
-		endif
-	endif
-	ifndef NO_DARWIN_PORTS
-		ifeq ($(shell test -d /opt/local/lib && echo y),y)
-			CFLAGS += -I/opt/local/include
-			LDFLAGS += -L/opt/local/lib
-		endif
-	endif
-endif
-
-ifndef NO_OPENSSL
-	EXTLIBS += -lssl
-	ifdef NEEDS_CRYPTO_WITH_SSL
-		EXTLIBS += -lcrypto
-	endif
-endif
-
-ifndef NO_PTHREADS
-	CFLAGS += $(PTHREADS_CFLAGS)
-	EXTLIBS += $(PTHREAD_LIBS)
-endif
-
-ifdef HAVE_CLOCK_GETTIME
-	CFLAGS += -DHAVE_CLOCK_GETTIME
-	EXTLIBS += -lrt
-endif
-
-ifdef NEEDS_LIBICONV
-	EXTLIBS += -liconv
-endif
-
-GIT_LIB = ../../libgit.a
-VCSSVN_LIB = ../../vcs-svn/lib.a
-XDIFF_LIB = ../../xdiff/lib.a
-
-LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB)
-
-QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
-QUIET_SUBDIR1 =
-
-ifneq ($(findstring $(MAKEFLAGS),w),w)
-PRINT_DIR = --no-print-directory
-else # "make -w"
-NO_SUBDIR = :
-endif
-
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
-	QUIET_CC      = @echo '   ' CC $@;
-	QUIET_LINK    = @echo '   ' LINK $@;
-	QUIET_SUBDIR0 = +@subdir=
-	QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
-	                $(MAKE) $(PRINT_DIR) -C $$subdir
-endif
-endif
-
-svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(XDIFF_LIB) $(GIT_LIB)
-	$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(EXTLIBS) -o $@ svn-fe.o $(LIBS)
-
-svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-	$(QUIET_CC)$(CC) $(CFLAGS) -I../../vcs-svn -o $*.o -c $<
-
-svn-fe.html: svn-fe.txt
-	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
-		MAN_TXT=../contrib/svn-fe/svn-fe.txt \
-		../contrib/svn-fe/$@
-
-svn-fe.1: svn-fe.txt
-	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
-		MAN_TXT=../contrib/svn-fe/svn-fe.txt \
-		../contrib/svn-fe/$@
-	$(MV) ../../Documentation/svn-fe.1 .
-
-../../vcs-svn/lib.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a
-
-../../xdiff/lib.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) xdiff/lib.a
-
-../../libgit.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
-
-clean:
-	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
-
-.PHONY: all clean FORCE
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
deleted file mode 100644
index f363505abb..0000000000
--- a/contrib/svn-fe/svn-fe.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * This file is in the public domain.
- * You may freely use, modify, distribute, and relicense it.
- */
-
-#include <stdlib.h>
-#include "svndump.h"
-
-int main(int argc, char **argv)
-{
-	if (svndump_init(NULL))
-		return 1;
-	svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
-			"refs/notes/svn/revs");
-	svndump_deinit();
-	svndump_reset();
-	return 0;
-}
diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt
deleted file mode 100644
index a3425f4770..0000000000
--- a/contrib/svn-fe/svn-fe.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-svn-fe(1)
-=========
-
-NAME
-----
-svn-fe - convert an SVN "dumpfile" to a fast-import stream
-
-SYNOPSIS
---------
-[verse]
-mkfifo backchannel &&
-svnadmin dump --deltas REPO |
-	svn-fe [url] 3<backchannel |
-	git fast-import --cat-blob-fd=3 3>backchannel
-
-DESCRIPTION
------------
-
-Converts a Subversion dumpfile into input suitable for
-git-fast-import(1) and similar importers. REPO is a path to a
-Subversion repository mirrored on the local disk. Remote Subversion
-repositories can be mirrored on local disk using the `svnsync`
-command.
-
-Note: this tool is very young.  The details of its commandline
-interface may change in backward incompatible ways.
-
-INPUT FORMAT
-------------
-Subversion's repository dump format is documented in full in
-`notes/dump-load-format.txt` from the Subversion source tree.
-Files in this format can be generated using the 'svnadmin dump' or
-'svk admin dump' command.
-
-OUTPUT FORMAT
--------------
-The fast-import format is documented by the git-fast-import(1)
-manual page.
-
-NOTES
------
-Subversion dumps do not record a separate author and committer for
-each revision, nor do they record a separate display name and email
-address for each author.  Like git-svn(1), 'svn-fe' will use the name
-
----------
-user <user@UUID>
----------
-
-as committer, where 'user' is the value of the `svn:author` property
-and 'UUID' the repository's identifier.
-
-To support incremental imports, 'svn-fe' puts a `git-svn-id` line at
-the end of each commit log message if passed a URL on the command
-line.  This line has the form `git-svn-id: URL@REVNO UUID`.
-
-The resulting repository will generally require further processing
-to put each project in its own repository and to separate the history
-of each branch.  The 'git filter-branch --subdirectory-filter' command
-may be useful for this purpose.
-
-BUGS
-----
-Empty directories and unknown properties are silently discarded.
-
-The exit status does not reflect whether an error was detected.
-
-SEE ALSO
---------
-git-svn(1), svn2git(1), svk(1), git-filter-branch(1), git-fast-import(1),
-https://svn.apache.org/repos/asf/subversion/trunk/notes/dump-load-format.txt
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
deleted file mode 100755
index 11ac6f6927..0000000000
--- a/contrib/svn-fe/svnrdump_sim.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/python
-"""
-Simulates svnrdump by replaying an existing dump from a file, taking care
-of the specified revision range.
-To simulate incremental imports the environment variable SVNRMAX can be set
-to the highest revision that should be available.
-"""
-import sys
-import os
-
-if sys.hexversion < 0x02040000:
-    # The limiter is the ValueError() calls. This may be too conservative
-    sys.stderr.write("svnrdump-sim.py: requires Python 2.4 or later.\n")
-    sys.exit(1)
-
-
-def getrevlimit():
-    var = 'SVNRMAX'
-    if var in os.environ:
-        return os.environ[var]
-    return None
-
-
-def writedump(url, lower, upper):
-    if url.startswith('sim://'):
-        filename = url[6:]
-        if filename[-1] == '/':
-            filename = filename[:-1]  # remove terminating slash
-    else:
-        raise ValueError('sim:// url required')
-    f = open(filename, 'r')
-    state = 'header'
-    wroterev = False
-    while(True):
-        l = f.readline()
-        if l == '':
-            break
-        if state == 'header' and l.startswith('Revision-number: '):
-            state = 'prefix'
-        if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
-            state = 'selection'
-        if not upper == 'HEAD' and state == 'selection' and \
-                l == 'Revision-number: %s\n' % upper:
-            break
-
-        if state == 'header' or state == 'selection':
-            if state == 'selection':
-                wroterev = True
-            sys.stdout.write(l)
-    return wroterev
-
-if __name__ == "__main__":
-    if not (len(sys.argv) in (3, 4, 5)):
-        print("usage: %s dump URL -rLOWER:UPPER")
-        sys.exit(1)
-    if not sys.argv[1] == 'dump':
-        raise NotImplementedError('only "dump" is suppported.')
-    url = sys.argv[2]
-    r = ('0', 'HEAD')
-    if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
-        r = sys.argv[3][2:].lstrip().split(':')
-    if not getrevlimit() is None:
-        r[1] = getrevlimit()
-    if writedump(url, r[0], r[1]):
-        ret = 0
-    else:
-        ret = 1
-    sys.exit(ret)
diff --git a/remote-testsvn.c b/remote-testsvn.c
deleted file mode 100644
index 3af708c5b6..0000000000
--- a/remote-testsvn.c
+++ /dev/null
@@ -1,337 +0,0 @@
-#include "cache.h"
-#include "refs.h"
-#include "remote.h"
-#include "object-store.h"
-#include "strbuf.h"
-#include "url.h"
-#include "exec-cmd.h"
-#include "run-command.h"
-#include "vcs-svn/svndump.h"
-#include "notes.h"
-#include "argv-array.h"
-
-static const char *url;
-static int dump_from_file;
-static const char *private_ref;
-static const char *remote_ref = "refs/heads/master";
-static const char *marksfilename, *notes_ref;
-struct rev_note { unsigned int rev_nr; };
-
-static int cmd_capabilities(const char *line);
-static int cmd_import(const char *line);
-static int cmd_list(const char *line);
-
-typedef int (*input_command_handler)(const char *);
-struct input_command_entry {
-	const char *name;
-	input_command_handler fn;
-	unsigned char batchable;	/* whether the command starts or is part of a batch */
-};
-
-static const struct input_command_entry input_command_list[] = {
-	{ "capabilities", cmd_capabilities, 0 },
-	{ "import", cmd_import, 1 },
-	{ "list", cmd_list, 0 },
-	{ NULL, NULL }
-};
-
-static int cmd_capabilities(const char *line)
-{
-	printf("import\n");
-	printf("bidi-import\n");
-	printf("refspec %s:%s\n\n", remote_ref, private_ref);
-	fflush(stdout);
-	return 0;
-}
-
-static void terminate_batch(void)
-{
-	/* terminate a current batch's fast-import stream */
-	printf("done\n");
-	fflush(stdout);
-}
-
-/* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */
-static char *read_ref_note(const struct object_id *oid)
-{
-	const struct object_id *note_oid;
-	char *msg = NULL;
-	unsigned long msglen;
-	enum object_type type;
-
-	init_notes(NULL, notes_ref, NULL, 0);
-	if (!(note_oid = get_note(NULL, oid)))
-		return NULL;	/* note tree not found */
-	if (!(msg = read_object_file(note_oid, &type, &msglen)))
-		error("Empty notes tree. %s", notes_ref);
-	else if (!msglen || type != OBJ_BLOB) {
-		error("Note contains unusable content. "
-			"Is something else using this notes tree? %s", notes_ref);
-		FREE_AND_NULL(msg);
-	}
-	free_notes(NULL);
-	return msg;
-}
-
-static int parse_rev_note(const char *msg, struct rev_note *res)
-{
-	const char *key, *value, *end;
-	size_t len;
-
-	while (*msg) {
-		end = strchrnul(msg, '\n');
-		len = end - msg;
-
-		key = "Revision-number: ";
-		if (starts_with(msg, key)) {
-			long i;
-			char *end;
-			value = msg + strlen(key);
-			i = strtol(value, &end, 0);
-			if (end == value || i < 0 || i > UINT32_MAX)
-				return -1;
-			res->rev_nr = i;
-			return 0;
-		}
-		msg += len + 1;
-	}
-	/* didn't find it */
-	return -1;
-}
-
-static int note2mark_cb(const struct object_id *object_oid,
-		const struct object_id *note_oid, char *note_path,
-		void *cb_data)
-{
-	FILE *file = (FILE *)cb_data;
-	char *msg;
-	unsigned long msglen;
-	enum object_type type;
-	struct rev_note note;
-
-	if (!(msg = read_object_file(note_oid, &type, &msglen)) ||
-			!msglen || type != OBJ_BLOB) {
-		free(msg);
-		return 1;
-	}
-	if (parse_rev_note(msg, &note))
-		return 2;
-	if (fprintf(file, ":%d %s\n", note.rev_nr, oid_to_hex(object_oid)) < 1)
-		return 3;
-	return 0;
-}
-
-static void regenerate_marks(void)
-{
-	int ret;
-	FILE *marksfile = xfopen(marksfilename, "w+");
-
-	ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
-	if (ret)
-		die("Regeneration of marks failed, returned %d.", ret);
-	fclose(marksfile);
-}
-
-static void check_or_regenerate_marks(int latestrev)
-{
-	FILE *marksfile;
-	struct strbuf sb = STRBUF_INIT;
-	struct strbuf line = STRBUF_INIT;
-	int found = 0;
-
-	if (latestrev < 1)
-		return;
-
-	init_notes(NULL, notes_ref, NULL, 0);
-	marksfile = fopen(marksfilename, "r");
-	if (!marksfile) {
-		regenerate_marks();
-		marksfile = xfopen(marksfilename, "r");
-		fclose(marksfile);
-	} else {
-		strbuf_addf(&sb, ":%d ", latestrev);
-		while (strbuf_getline_lf(&line, marksfile) != EOF) {
-			if (starts_with(line.buf, sb.buf)) {
-				found++;
-				break;
-			}
-		}
-		fclose(marksfile);
-		if (!found)
-			regenerate_marks();
-	}
-	free_notes(NULL);
-	strbuf_release(&sb);
-	strbuf_release(&line);
-}
-
-static int cmd_import(const char *line)
-{
-	int code;
-	int dumpin_fd;
-	char *note_msg;
-	struct object_id head_oid;
-	unsigned int startrev;
-	struct child_process svndump_proc = CHILD_PROCESS_INIT;
-	const char *command = "svnrdump";
-
-	if (read_ref(private_ref, &head_oid))
-		startrev = 0;
-	else {
-		note_msg = read_ref_note(&head_oid);
-		if(note_msg == NULL) {
-			warning("No note found for %s.", private_ref);
-			startrev = 0;
-		} else {
-			struct rev_note note = { 0 };
-			if (parse_rev_note(note_msg, &note))
-				die("Revision number couldn't be parsed from note.");
-			startrev = note.rev_nr + 1;
-			free(note_msg);
-		}
-	}
-	check_or_regenerate_marks(startrev - 1);
-
-	if (dump_from_file) {
-		dumpin_fd = open(url, O_RDONLY);
-		if(dumpin_fd < 0)
-			die_errno("Couldn't open svn dump file %s.", url);
-	} else {
-		svndump_proc.out = -1;
-		argv_array_push(&svndump_proc.args, command);
-		argv_array_push(&svndump_proc.args, "dump");
-		argv_array_push(&svndump_proc.args, url);
-		argv_array_pushf(&svndump_proc.args, "-r%u:HEAD", startrev);
-
-		code = start_command(&svndump_proc);
-		if (code)
-			die("Unable to start %s, code %d", command, code);
-		dumpin_fd = svndump_proc.out;
-	}
-	/* setup marks file import/export */
-	printf("feature import-marks-if-exists=%s\n"
-			"feature export-marks=%s\n", marksfilename, marksfilename);
-
-	svndump_init_fd(dumpin_fd, STDIN_FILENO);
-	svndump_read(url, private_ref, notes_ref);
-	svndump_deinit();
-	svndump_reset();
-
-	close(dumpin_fd);
-	if (!dump_from_file) {
-		code = finish_command(&svndump_proc);
-		if (code)
-			warning("%s, returned %d", command, code);
-	}
-
-	return 0;
-}
-
-static int cmd_list(const char *line)
-{
-	printf("? %s\n\n", remote_ref);
-	fflush(stdout);
-	return 0;
-}
-
-static int do_command(struct strbuf *line)
-{
-	const struct input_command_entry *p = input_command_list;
-	static struct string_list batchlines = STRING_LIST_INIT_DUP;
-	static const struct input_command_entry *batch_cmd;
-	/*
-	 * commands can be grouped together in a batch.
-	 * Batches are ended by \n. If no batch is active the program ends.
-	 * During a batch all lines are buffered and passed to the handler function
-	 * when the batch is terminated.
-	 */
-	if (line->len == 0) {
-		if (batch_cmd) {
-			struct string_list_item *item;
-			for_each_string_list_item(item, &batchlines)
-				batch_cmd->fn(item->string);
-			terminate_batch();
-			batch_cmd = NULL;
-			string_list_clear(&batchlines, 0);
-			return 0;	/* end of the batch, continue reading other commands. */
-		}
-		return 1;	/* end of command stream, quit */
-	}
-	if (batch_cmd) {
-		if (!starts_with(batch_cmd->name, line->buf))
-			die("Active %s batch interrupted by %s", batch_cmd->name, line->buf);
-		/* buffer batch lines */
-		string_list_append(&batchlines, line->buf);
-		return 0;
-	}
-
-	for (p = input_command_list; p->name; p++) {
-		if (starts_with(line->buf, p->name) && (strlen(p->name) == line->len ||
-				line->buf[strlen(p->name)] == ' ')) {
-			if (p->batchable) {
-				batch_cmd = p;
-				string_list_append(&batchlines, line->buf);
-				return 0;
-			}
-			return p->fn(line->buf);
-		}
-	}
-	die("Unknown command '%s'\n", line->buf);
-	return 0;
-}
-
-int cmd_main(int argc, const char **argv)
-{
-	struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
-			private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
-			notes_ref_sb = STRBUF_INIT;
-	static struct remote *remote;
-	const char *url_in;
-
-	setup_git_directory();
-	if (argc < 2 || argc > 3) {
-		usage("git-remote-svn <remote-name> [<url>]");
-		return 1;
-	}
-
-	remote = remote_get(argv[1]);
-	url_in = (argc == 3) ? argv[2] : remote->url[0];
-
-	if (starts_with(url_in, "file://")) {
-		dump_from_file = 1;
-		url = url_decode(url_in + sizeof("file://")-1);
-	} else {
-		dump_from_file = 0;
-		end_url_with_slash(&url_sb, url_in);
-		url = url_sb.buf;
-	}
-
-	strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name);
-	private_ref = private_ref_sb.buf;
-
-	strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
-	notes_ref = notes_ref_sb.buf;
-
-	strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks",
-		get_git_dir(), remote->name);
-	marksfilename = marksfilename_sb.buf;
-
-	while (1) {
-		if (strbuf_getline_lf(&buf, stdin) == EOF) {
-			if (ferror(stdin))
-				die("Error reading command stream");
-			else
-				die("Unexpected end of command stream");
-		}
-		if (do_command(&buf))
-			break;
-		strbuf_reset(&buf);
-	}
-
-	strbuf_release(&buf);
-	strbuf_release(&url_sb);
-	strbuf_release(&private_ref_sb);
-	strbuf_release(&notes_ref_sb);
-	strbuf_release(&marksfilename_sb);
-	return 0;
-}
diff --git a/t/helper/test-line-buffer.c b/t/helper/test-line-buffer.c
deleted file mode 100644
index 078dd7e29d..0000000000
--- a/t/helper/test-line-buffer.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * test-line-buffer.c: code to exercise the svn importer's input helper
- */
-
-#include "git-compat-util.h"
-#include "strbuf.h"
-#include "vcs-svn/line_buffer.h"
-
-static uint32_t strtouint32(const char *s)
-{
-	char *end;
-	uintmax_t n = strtoumax(s, &end, 10);
-	if (*s == '\0' || *end != '\0')
-		die("invalid count: %s", s);
-	return (uint32_t) n;
-}
-
-static void handle_command(const char *command, const char *arg, struct line_buffer *buf)
-{
-	if (starts_with(command, "binary ")) {
-		struct strbuf sb = STRBUF_INIT;
-		strbuf_addch(&sb, '>');
-		buffer_read_binary(buf, &sb, strtouint32(arg));
-		fwrite(sb.buf, 1, sb.len, stdout);
-		strbuf_release(&sb);
-	} else if (starts_with(command, "copy ")) {
-		buffer_copy_bytes(buf, strtouint32(arg));
-	} else if (starts_with(command, "skip ")) {
-		buffer_skip_bytes(buf, strtouint32(arg));
-	} else {
-		die("unrecognized command: %s", command);
-	}
-}
-
-static void handle_line(const char *line, struct line_buffer *stdin_buf)
-{
-	const char *arg = strchr(line, ' ');
-	if (!arg)
-		die("no argument in line: %s", line);
-	handle_command(line, arg + 1, stdin_buf);
-}
-
-int cmd_main(int argc, const char **argv)
-{
-	struct line_buffer stdin_buf = LINE_BUFFER_INIT;
-	struct line_buffer file_buf = LINE_BUFFER_INIT;
-	struct line_buffer *input = &stdin_buf;
-	const char *filename;
-	char *s;
-
-	if (argc == 1)
-		filename = NULL;
-	else if (argc == 2)
-		filename = argv[1];
-	else
-		usage("test-line-buffer [file | &fd] < script");
-
-	if (buffer_init(&stdin_buf, NULL))
-		die_errno("open error");
-	if (filename) {
-		if (*filename == '&') {
-			if (buffer_fdinit(&file_buf, strtouint32(filename + 1)))
-				die_errno("error opening fd %s", filename + 1);
-		} else {
-			if (buffer_init(&file_buf, filename))
-				die_errno("error opening %s", filename);
-		}
-		input = &file_buf;
-	}
-
-	while ((s = buffer_read_line(&stdin_buf)))
-		handle_line(s, input);
-
-	if (filename && buffer_deinit(&file_buf))
-		die("error reading from %s", filename);
-	if (buffer_deinit(&stdin_buf))
-		die("input error");
-	if (ferror(stdout))
-		die("output error");
-	return 0;
-}
diff --git a/t/helper/test-svn-fe.c b/t/helper/test-svn-fe.c
deleted file mode 100644
index 7667c0803f..0000000000
--- a/t/helper/test-svn-fe.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * test-svn-fe: Code to exercise the svn import lib
- */
-
-#include "git-compat-util.h"
-#include "vcs-svn/svndump.h"
-#include "vcs-svn/svndiff.h"
-#include "vcs-svn/sliding_window.h"
-#include "vcs-svn/line_buffer.h"
-
-static const char test_svnfe_usage[] =
-	"test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)";
-
-static int apply_delta(int argc, const char **argv)
-{
-	struct line_buffer preimage = LINE_BUFFER_INIT;
-	struct line_buffer delta = LINE_BUFFER_INIT;
-	struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage, -1);
-
-	if (argc != 5)
-		usage(test_svnfe_usage);
-
-	if (buffer_init(&preimage, argv[2]))
-		die_errno("cannot open preimage");
-	if (buffer_init(&delta, argv[3]))
-		die_errno("cannot open delta");
-	if (svndiff0_apply(&delta, (off_t) strtoumax(argv[4], NULL, 0),
-					&preimage_view, stdout))
-		return 1;
-	if (buffer_deinit(&preimage))
-		die_errno("cannot close preimage");
-	if (buffer_deinit(&delta))
-		die_errno("cannot close delta");
-	strbuf_release(&preimage_view.buf);
-	return 0;
-}
-
-int cmd_main(int argc, const char **argv)
-{
-	if (argc == 2) {
-		if (svndump_init(argv[1]))
-			return 1;
-		svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
-		svndump_deinit();
-		svndump_reset();
-		return 0;
-	}
-
-	if (argc >= 2 && !strcmp(argv[1], "-d"))
-		return apply_delta(argc, argv);
-	usage(test_svnfe_usage);
-}
diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
deleted file mode 100755
index 6fca08e5e3..0000000000
--- a/t/t9020-remote-svn.sh
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/bin/sh
-
-test_description='tests remote-svn'
-
-. ./test-lib.sh
-
-MARKSPATH=.git/info/fast-import/remote-svn
-
-if ! test_have_prereq PYTHON
-then
-	skip_all='skipping remote-svn tests, python not available'
-	test_done
-fi
-
-# Override svnrdump with our simulator
-PATH="$HOME:$PATH"
-export PATH PYTHON_PATH GIT_BUILD_DIR
-
-write_script "$HOME/svnrdump" <<\EOF
-exec "$PYTHON_PATH" "$GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py" "$@"
-EOF
-
-init_git () {
-	rm -fr .git &&
-	git init &&
-	#git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
-	# let's reuse an existing dump file!?
-	git remote add svnsim "testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump"
-	git remote add svnfile "testsvn::file://$TEST_DIRECTORY/t9154/svn.dump"
-}
-
-if test -e "$GIT_BUILD_DIR/git-remote-testsvn"
-then
-	test_set_prereq REMOTE_SVN
-fi
-
-test_debug '
-	git --version
-	type git
-	type svnrdump
-'
-
-test_expect_success REMOTE_SVN 'simple fetch' '
-	init_git &&
-	git fetch svnsim &&
-	test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
-	cp .git/refs/remotes/svnsim/master master.good
-'
-
-test_debug '
-	cat .git/refs/svn/svnsim/master
-	cat .git/refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'repeated fetch, nothing shall change' '
-	git fetch svnsim &&
-	test_cmp master.good .git/refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'fetch from a file:// url gives the same result' '
-	git fetch svnfile
-'
-
-test_expect_failure REMOTE_SVN 'the sha1 differ because the git-svn-id line in the commit msg contains the url' '
-	test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master
-'
-
-test_expect_success REMOTE_SVN 'mark-file regeneration' '
-	# filter out any other marks, that can not be regenerated. Only up to 3 digit revisions are allowed here
-	grep ":[0-9]\{1,3\} " $MARKSPATH/svnsim.marks > $MARKSPATH/svnsim.marks.old &&
-	rm $MARKSPATH/svnsim.marks &&
-	git fetch svnsim &&
-	test_cmp $MARKSPATH/svnsim.marks.old $MARKSPATH/svnsim.marks
-'
-
-test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' '
-	SVNRMAX=3 &&
-	export SVNRMAX &&
-	init_git &&
-	git fetch svnsim &&
-	test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
-	unset SVNRMAX &&
-	git fetch svnsim &&
-	test_cmp master.good .git/refs/remotes/svnsim/master
-'
-
-test_debug 'git branch -a'
-
-test_done
diff --git a/vcs-svn/LICENSE b/vcs-svn/LICENSE
deleted file mode 100644
index eb91858b82..0000000000
--- a/vcs-svn/LICENSE
+++ /dev/null
@@ -1,32 +0,0 @@
-Copyright (C) 2010 David Barr <david.barr@cordelta.com>.
-All rights reserved.
-
-Copyright (C) 2010 Jonathan Nieder <jrnieder@gmail.com>.
-
-Copyright (C) 2005 Stefan Hegny, hydrografix Consulting GmbH,
-Frankfurt/Main, Germany
-and others, see http://svn2cc.sarovar.org
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice(s), this list of conditions and the following disclaimer
-   unmodified other than the allowable addition of one or more
-   copyright notices.
-2. Redistributions in binary form must reproduce the above copyright
-   notice(s), this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the
-   distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
deleted file mode 100644
index b5b8913cb0..0000000000
--- a/vcs-svn/fast_export.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "cache.h"
-#include "quote.h"
-#include "fast_export.h"
-#include "strbuf.h"
-#include "svndiff.h"
-#include "sliding_window.h"
-#include "line_buffer.h"
-
-#define MAX_GITSVN_LINE_LEN 4096
-
-static uint32_t first_commit_done;
-static struct line_buffer postimage = LINE_BUFFER_INIT;
-static struct line_buffer report_buffer = LINE_BUFFER_INIT;
-
-/* NEEDSWORK: move to fast_export_init() */
-static int init_postimage(void)
-{
-	static int postimage_initialized;
-	if (postimage_initialized)
-		return 0;
-	postimage_initialized = 1;
-	return buffer_tmpfile_init(&postimage);
-}
-
-void fast_export_init(int fd)
-{
-	first_commit_done = 0;
-	if (buffer_fdinit(&report_buffer, fd))
-		die_errno("cannot read from file descriptor %d", fd);
-}
-
-void fast_export_deinit(void)
-{
-	if (buffer_deinit(&report_buffer))
-		die_errno("error closing fast-import feedback stream");
-}
-
-void fast_export_delete(const char *path)
-{
-	putchar('D');
-	putchar(' ');
-	quote_c_style(path, NULL, stdout, 0);
-	putchar('\n');
-}
-
-static void fast_export_truncate(const char *path, uint32_t mode)
-{
-	fast_export_modify(path, mode, "inline");
-	printf("data 0\n\n");
-}
-
-void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
-{
-	/* Mode must be 100644, 100755, 120000, or 160000. */
-	if (!dataref) {
-		fast_export_truncate(path, mode);
-		return;
-	}
-	printf("M %06"PRIo32" %s ", mode, dataref);
-	quote_c_style(path, NULL, stdout, 0);
-	putchar('\n');
-}
-
-void fast_export_begin_note(uint32_t revision, const char *author,
-		const char *log, timestamp_t timestamp, const char *note_ref)
-{
-	static int firstnote = 1;
-	size_t loglen = strlen(log);
-	printf("commit %s\n", note_ref);
-	printf("committer %s <%s@%s> %"PRItime" +0000\n", author, author, "local", timestamp);
-	printf("data %"PRIuMAX"\n", (uintmax_t)loglen);
-	fwrite(log, loglen, 1, stdout);
-	if (firstnote) {
-		if (revision > 1)
-			printf("from %s^0", note_ref);
-		firstnote = 0;
-	}
-	fputc('\n', stdout);
-}
-
-void fast_export_note(const char *committish, const char *dataref)
-{
-	printf("N %s %s\n", dataref, committish);
-}
-
-static char gitsvnline[MAX_GITSVN_LINE_LEN];
-void fast_export_begin_commit(uint32_t revision, const char *author,
-			const struct strbuf *log,
-			const char *uuid, const char *url,
-			timestamp_t timestamp, const char *local_ref)
-{
-	static const struct strbuf empty = STRBUF_INIT;
-	if (!log)
-		log = &empty;
-	if (*uuid && *url) {
-		snprintf(gitsvnline, MAX_GITSVN_LINE_LEN,
-				"\n\ngit-svn-id: %s@%"PRIu32" %s\n",
-				 url, revision, uuid);
-	} else {
-		*gitsvnline = '\0';
-	}
-	printf("commit %s\n", local_ref);
-	printf("mark :%"PRIu32"\n", revision);
-	printf("committer %s <%s@%s> %"PRItime" +0000\n",
-		   *author ? author : "nobody",
-		   *author ? author : "nobody",
-		   *uuid ? uuid : "local", timestamp);
-	printf("data %"PRIuMAX"\n",
-		(uintmax_t) (log->len + strlen(gitsvnline)));
-	fwrite(log->buf, log->len, 1, stdout);
-	printf("%s\n", gitsvnline);
-	if (!first_commit_done) {
-		if (revision > 1)
-			printf("from :%"PRIu32"\n", revision - 1);
-		first_commit_done = 1;
-	}
-}
-
-void fast_export_end_commit(uint32_t revision)
-{
-	printf("progress Imported commit %"PRIu32".\n\n", revision);
-}
-
-static void ls_from_rev(uint32_t rev, const char *path)
-{
-	/* ls :5 path/to/old/file */
-	printf("ls :%"PRIu32" ", rev);
-	quote_c_style(path, NULL, stdout, 0);
-	putchar('\n');
-	fflush(stdout);
-}
-
-static void ls_from_active_commit(const char *path)
-{
-	/* ls "path/to/file" */
-	printf("ls \"");
-	quote_c_style(path, NULL, stdout, 1);
-	printf("\"\n");
-	fflush(stdout);
-}
-
-static const char *get_response_line(void)
-{
-	const char *line = buffer_read_line(&report_buffer);
-	if (line)
-		return line;
-	if (buffer_ferror(&report_buffer))
-		die_errno("error reading from fast-import");
-	die("unexpected end of fast-import feedback");
-}
-
-static void die_short_read(struct line_buffer *input)
-{
-	if (buffer_ferror(input))
-		die_errno("error reading dump file");
-	die("invalid dump: unexpected end of file");
-}
-
-static int parse_cat_response_line(const char *header, off_t *len)
-{
-	uintmax_t n;
-	const char *type;
-	const char *end;
-
-	if (ends_with(header, " missing"))
-		return error("cat-blob reports missing blob: %s", header);
-	type = strstr(header, " blob ");
-	if (!type)
-		return error("cat-blob header has wrong object type: %s", header);
-	n = strtoumax(type + strlen(" blob "), (char **) &end, 10);
-	if (end == type + strlen(" blob "))
-		return error("cat-blob header does not contain length: %s", header);
-	if (memchr(type + strlen(" blob "), '-', end - type - strlen(" blob ")))
-		return error("cat-blob header contains negative length: %s", header);
-	if (n == UINTMAX_MAX || n > maximum_signed_value_of_type(off_t))
-		return error("blob too large for current definition of off_t");
-	*len = n;
-	if (*end)
-		return error("cat-blob header contains garbage after length: %s", header);
-	return 0;
-}
-
-static void check_preimage_overflow(off_t a, off_t b)
-{
-	if (signed_add_overflows(a, b))
-		die("blob too large for current definition of off_t");
-}
-
-static long apply_delta(off_t len, struct line_buffer *input,
-			const char *old_data, uint32_t old_mode)
-{
-	long ret;
-	struct sliding_view preimage = SLIDING_VIEW_INIT(&report_buffer, 0);
-	FILE *out;
-
-	if (init_postimage() || !(out = buffer_tmpfile_rewind(&postimage)))
-		die("cannot open temporary file for blob retrieval");
-	if (old_data) {
-		const char *response;
-		printf("cat-blob %s\n", old_data);
-		fflush(stdout);
-		response = get_response_line();
-		if (parse_cat_response_line(response, &preimage.max_off))
-			die("invalid cat-blob response: %s", response);
-		check_preimage_overflow(preimage.max_off, 1);
-	}
-	if (old_mode == S_IFLNK) {
-		strbuf_addstr(&preimage.buf, "link ");
-		check_preimage_overflow(preimage.max_off, strlen("link "));
-		preimage.max_off += strlen("link ");
-		check_preimage_overflow(preimage.max_off, 1);
-	}
-	if (svndiff0_apply(input, len, &preimage, out))
-		die("cannot apply delta");
-	if (old_data) {
-		/* Read the remainder of preimage and trailing newline. */
-		assert(!signed_add_overflows(preimage.max_off, 1));
-		preimage.max_off++;	/* room for newline */
-		if (move_window(&preimage, preimage.max_off - 1, 1))
-			die("cannot seek to end of input");
-		if (preimage.buf.buf[0] != '\n')
-			die("missing newline after cat-blob response");
-	}
-	ret = buffer_tmpfile_prepare_to_read(&postimage);
-	if (ret < 0)
-		die("cannot read temporary file for blob retrieval");
-	strbuf_release(&preimage.buf);
-	return ret;
-}
-
-void fast_export_buf_to_data(const struct strbuf *data)
-{
-	printf("data %"PRIuMAX"\n", (uintmax_t)data->len);
-	fwrite(data->buf, data->len, 1, stdout);
-	fputc('\n', stdout);
-}
-
-void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
-{
-	assert(len >= 0);
-	if (mode == S_IFLNK) {
-		/* svn symlink blobs start with "link " */
-		if (len < 5)
-			die("invalid dump: symlink too short for \"link\" prefix");
-		len -= 5;
-		if (buffer_skip_bytes(input, 5) != 5)
-			die_short_read(input);
-	}
-	printf("data %"PRIuMAX"\n", (uintmax_t) len);
-	if (buffer_copy_bytes(input, len) != len)
-		die_short_read(input);
-	fputc('\n', stdout);
-}
-
-static int parse_ls_response(const char *response, uint32_t *mode,
-					struct strbuf *dataref)
-{
-	const char *tab;
-	const char *response_end;
-
-	assert(response);
-	response_end = response + strlen(response);
-
-	if (*response == 'm') {	/* Missing. */
-		errno = ENOENT;
-		return -1;
-	}
-
-	/* Mode. */
-	if (response_end - response < (signed) strlen("100644") ||
-	    response[strlen("100644")] != ' ')
-		die("invalid ls response: missing mode: %s", response);
-	*mode = 0;
-	for (; *response != ' '; response++) {
-		char ch = *response;
-		if (ch < '0' || ch > '7')
-			die("invalid ls response: mode is not octal: %s", response);
-		*mode *= 8;
-		*mode += ch - '0';
-	}
-
-	/* ' blob ' or ' tree ' */
-	if (response_end - response < (signed) strlen(" blob ") ||
-	    (response[1] != 'b' && response[1] != 't'))
-		die("unexpected ls response: not a tree or blob: %s", response);
-	response += strlen(" blob ");
-
-	/* Dataref. */
-	tab = memchr(response, '\t', response_end - response);
-	if (!tab)
-		die("invalid ls response: missing tab: %s", response);
-	strbuf_add(dataref, response, tab - response);
-	return 0;
-}
-
-int fast_export_ls_rev(uint32_t rev, const char *path,
-				uint32_t *mode, struct strbuf *dataref)
-{
-	ls_from_rev(rev, path);
-	return parse_ls_response(get_response_line(), mode, dataref);
-}
-
-int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)
-{
-	ls_from_active_commit(path);
-	return parse_ls_response(get_response_line(), mode, dataref);
-}
-
-const char *fast_export_read_path(const char *path, uint32_t *mode_out)
-{
-	int err;
-	static struct strbuf buf = STRBUF_INIT;
-
-	strbuf_reset(&buf);
-	err = fast_export_ls(path, mode_out, &buf);
-	if (err) {
-		if (errno != ENOENT)
-			BUG("unexpected fast_export_ls error: %s",
-			    strerror(errno));
-		/* Treat missing paths as directories. */
-		*mode_out = S_IFDIR;
-		return NULL;
-	}
-	return buf.buf;
-}
-
-void fast_export_copy(uint32_t revision, const char *src, const char *dst)
-{
-	int err;
-	uint32_t mode;
-	static struct strbuf data = STRBUF_INIT;
-
-	strbuf_reset(&data);
-	err = fast_export_ls_rev(revision, src, &mode, &data);
-	if (err) {
-		if (errno != ENOENT)
-			BUG("unexpected fast_export_ls_rev error: %s",
-			    strerror(errno));
-		fast_export_delete(dst);
-		return;
-	}
-	fast_export_modify(dst, mode, data.buf);
-}
-
-void fast_export_blob_delta(uint32_t mode,
-				uint32_t old_mode, const char *old_data,
-				off_t len, struct line_buffer *input)
-{
-	long postimage_len;
-
-	assert(len >= 0);
-	postimage_len = apply_delta(len, input, old_data, old_mode);
-	if (mode == S_IFLNK) {
-		buffer_skip_bytes(&postimage, strlen("link "));
-		postimage_len -= strlen("link ");
-	}
-	printf("data %ld\n", postimage_len);
-	buffer_copy_bytes(&postimage, postimage_len);
-	fputc('\n', stdout);
-}
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
deleted file mode 100644
index 60b79c35b9..0000000000
--- a/vcs-svn/fast_export.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef FAST_EXPORT_H_
-#define FAST_EXPORT_H_
-
-struct strbuf;
-struct line_buffer;
-
-void fast_export_init(int fd);
-void fast_export_deinit(void);
-
-void fast_export_delete(const char *path);
-void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
-void fast_export_note(const char *committish, const char *dataref);
-void fast_export_begin_note(uint32_t revision, const char *author,
-		const char *log, timestamp_t timestamp, const char *note_ref);
-void fast_export_begin_commit(uint32_t revision, const char *author,
-			const struct strbuf *log, const char *uuid,const char *url,
-			timestamp_t timestamp, const char *local_ref);
-void fast_export_end_commit(uint32_t revision);
-void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);
-void fast_export_buf_to_data(const struct strbuf *data);
-void fast_export_blob_delta(uint32_t mode,
-			uint32_t old_mode, const char *old_data,
-			off_t len, struct line_buffer *input);
-
-/* If there is no such file at that rev, returns -1, errno == ENOENT. */
-int fast_export_ls_rev(uint32_t rev, const char *path,
-			uint32_t *mode_out, struct strbuf *dataref_out);
-int fast_export_ls(const char *path,
-			uint32_t *mode_out, struct strbuf *dataref_out);
-
-void fast_export_copy(uint32_t revision, const char *src, const char *dst);
-const char *fast_export_read_path(const char *path, uint32_t *mode_out);
-
-#endif
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
deleted file mode 100644
index e416caf8a4..0000000000
--- a/vcs-svn/line_buffer.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "line_buffer.h"
-#include "strbuf.h"
-
-#define COPY_BUFFER_LEN 4096
-
-int buffer_init(struct line_buffer *buf, const char *filename)
-{
-	buf->infile = filename ? fopen(filename, "r") : stdin;
-	if (!buf->infile)
-		return -1;
-	return 0;
-}
-
-int buffer_fdinit(struct line_buffer *buf, int fd)
-{
-	buf->infile = fdopen(fd, "r");
-	if (!buf->infile)
-		return -1;
-	return 0;
-}
-
-int buffer_tmpfile_init(struct line_buffer *buf)
-{
-	buf->infile = tmpfile();
-	if (!buf->infile)
-		return -1;
-	return 0;
-}
-
-int buffer_deinit(struct line_buffer *buf)
-{
-	int err;
-	if (buf->infile == stdin)
-		return ferror(buf->infile);
-	err = ferror(buf->infile);
-	err |= fclose(buf->infile);
-	return err;
-}
-
-FILE *buffer_tmpfile_rewind(struct line_buffer *buf)
-{
-	rewind(buf->infile);
-	return buf->infile;
-}
-
-long buffer_tmpfile_prepare_to_read(struct line_buffer *buf)
-{
-	long pos = ftell(buf->infile);
-	if (pos < 0)
-		return error_errno("ftell error");
-	if (fseek(buf->infile, 0, SEEK_SET))
-		return error_errno("seek error");
-	return pos;
-}
-
-int buffer_ferror(struct line_buffer *buf)
-{
-	return ferror(buf->infile);
-}
-
-int buffer_read_char(struct line_buffer *buf)
-{
-	return fgetc(buf->infile);
-}
-
-/* Read a line without trailing newline. */
-char *buffer_read_line(struct line_buffer *buf)
-{
-	char *end;
-	if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile))
-		/* Error or data exhausted. */
-		return NULL;
-	end = buf->line_buffer + strlen(buf->line_buffer);
-	if (end[-1] == '\n')
-		end[-1] = '\0';
-	else if (feof(buf->infile))
-		; /* No newline at end of file.  That's fine. */
-	else
-		/*
-		 * Line was too long.
-		 * There is probably a saner way to deal with this,
-		 * but for now let's return an error.
-		 */
-		return NULL;
-	return buf->line_buffer;
-}
-
-size_t buffer_read_binary(struct line_buffer *buf,
-				struct strbuf *sb, size_t size)
-{
-	return strbuf_fread(sb, size, buf->infile);
-}
-
-off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
-{
-	char byte_buffer[COPY_BUFFER_LEN];
-	off_t done = 0;
-	while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
-		off_t len = nbytes - done;
-		size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
-		in = fread(byte_buffer, 1, in, buf->infile);
-		done += in;
-		fwrite(byte_buffer, 1, in, stdout);
-		if (ferror(stdout))
-			return done + buffer_skip_bytes(buf, nbytes - done);
-	}
-	return done;
-}
-
-off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
-{
-	char byte_buffer[COPY_BUFFER_LEN];
-	off_t done = 0;
-	while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
-		off_t len = nbytes - done;
-		size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
-		done += fread(byte_buffer, 1, in, buf->infile);
-	}
-	return done;
-}
diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h
deleted file mode 100644
index ee23b4f490..0000000000
--- a/vcs-svn/line_buffer.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef LINE_BUFFER_H_
-#define LINE_BUFFER_H_
-
-#include "strbuf.h"
-
-#define LINE_BUFFER_LEN 10000
-
-struct line_buffer {
-	char line_buffer[LINE_BUFFER_LEN];
-	FILE *infile;
-};
-#define LINE_BUFFER_INIT { "", NULL }
-
-int buffer_init(struct line_buffer *buf, const char *filename);
-int buffer_fdinit(struct line_buffer *buf, int fd);
-int buffer_deinit(struct line_buffer *buf);
-
-int buffer_tmpfile_init(struct line_buffer *buf);
-FILE *buffer_tmpfile_rewind(struct line_buffer *buf);	/* prepare to write. */
-long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);
-
-int buffer_ferror(struct line_buffer *buf);
-char *buffer_read_line(struct line_buffer *buf);
-int buffer_read_char(struct line_buffer *buf);
-size_t buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, size_t len);
-/* Returns number of bytes read (not necessarily written). */
-off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);
-off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);
-
-#endif
diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt
deleted file mode 100644
index 8e139eb22d..0000000000
--- a/vcs-svn/line_buffer.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-line_buffer API
-===============
-
-The line_buffer library provides a convenient interface for
-mostly-line-oriented input.
-
-Each line is not permitted to exceed 10000 bytes.  The provided
-functions are not thread-safe or async-signal-safe, and like
-`fgets()`, they generally do not function correctly if interrupted
-by a signal without SA_RESTART set.
-
-Calling sequence
-----------------
-
-The calling program:
-
- - initializes a `struct line_buffer` to LINE_BUFFER_INIT
- - specifies a file to read with `buffer_init`
- - processes input with `buffer_read_line`, `buffer_skip_bytes`,
-   and `buffer_copy_bytes`
- - closes the file with `buffer_deinit`, perhaps to start over and
-   read another file.
-
-When finished, the caller can use `buffer_reset` to deallocate
-resources.
-
-Using temporary files
----------------------
-
-Temporary files provide a place to store data that should not outlive
-the calling program.  A program
-
- - initializes a `struct line_buffer` to LINE_BUFFER_INIT
- - requests a temporary file with `buffer_tmpfile_init`
- - acquires an output handle by calling `buffer_tmpfile_rewind`
- - uses standard I/O functions like `fprintf` and `fwrite` to fill
-   the temporary file
- - declares writing is over with `buffer_tmpfile_prepare_to_read`
- - can re-read what was written with `buffer_read_line`,
-   `buffer_copy_bytes`, and so on
- - can reuse the temporary file by calling `buffer_tmpfile_rewind`
-   again
- - removes the temporary file with `buffer_deinit`, perhaps to
-   reuse the line_buffer for some other file.
-
-When finished, the calling program can use `buffer_reset` to deallocate
-resources.
-
-Functions
----------
-
-`buffer_init`, `buffer_fdinit`::
-	Open the named file or file descriptor for input.
-	buffer_init(buf, NULL) prepares to read from stdin.
-	On failure, returns -1 (with errno indicating the nature
-	of the failure).
-
-`buffer_deinit`::
-	Stop reading from the current file (closing it unless
-	it was stdin).  Returns nonzero if `fclose` fails or
-	the error indicator was set.
-
-`buffer_read_line`::
-	Read a line and strip off the trailing newline.
-	On failure or end of file, returns NULL.
-
-`buffer_copy_bytes`::
-	Read `len` bytes of input and dump them to the standard output
-	stream.  Returns early for error or end of file.
-
-`buffer_skip_bytes`::
-	Discards `len` bytes from the input stream (stopping early
-	if necessary because of an error or eof).  Return value is
-	the number of bytes successfully read.
-
-`buffer_reset`::
-	Deallocates non-static buffers.
diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c
deleted file mode 100644
index 06d273c9e8..0000000000
--- a/vcs-svn/sliding_window.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "sliding_window.h"
-#include "line_buffer.h"
-#include "strbuf.h"
-
-static int input_error(struct line_buffer *file)
-{
-	if (!buffer_ferror(file))
-		return error("delta preimage ends early");
-	return error_errno("cannot read delta preimage");
-}
-
-static int skip_or_whine(struct line_buffer *file, off_t gap)
-{
-	if (buffer_skip_bytes(file, gap) != gap)
-		return input_error(file);
-	return 0;
-}
-
-static int read_to_fill_or_whine(struct line_buffer *file,
-				struct strbuf *buf, size_t width)
-{
-	buffer_read_binary(file, buf, width - buf->len);
-	if (buf->len != width)
-		return input_error(file);
-	return 0;
-}
-
-static int check_offset_overflow(off_t offset, uintmax_t len)
-{
-	if (len > maximum_signed_value_of_type(off_t))
-		return error("unrepresentable length in delta: "
-				"%"PRIuMAX" > OFF_MAX", len);
-	if (signed_add_overflows(offset, (off_t) len))
-		return error("unrepresentable offset in delta: "
-				"%"PRIuMAX" + %"PRIuMAX" > OFF_MAX",
-				(uintmax_t) offset, len);
-	return 0;
-}
-
-int move_window(struct sliding_view *view, off_t off, size_t width)
-{
-	off_t file_offset;
-	assert(view);
-	assert(view->width <= view->buf.len);
-	assert(!check_offset_overflow(view->off, view->buf.len));
-
-	if (check_offset_overflow(off, width))
-		return -1;
-	if (off < view->off || off + width < view->off + view->width)
-		return error("invalid delta: window slides left");
-	if (view->max_off >= 0 && view->max_off < off + (off_t) width)
-		return error("delta preimage ends early");
-
-	file_offset = view->off + view->buf.len;
-	if (off < file_offset) {
-		/* Move the overlapping region into place. */
-		strbuf_remove(&view->buf, 0, off - view->off);
-	} else {
-		/* Seek ahead to skip the gap. */
-		if (skip_or_whine(view->file, off - file_offset))
-			return -1;
-		strbuf_setlen(&view->buf, 0);
-	}
-
-	if (view->buf.len > width)
-		; /* Already read. */
-	else if (read_to_fill_or_whine(view->file, &view->buf, width))
-		return -1;
-
-	view->off = off;
-	view->width = width;
-	return 0;
-}
diff --git a/vcs-svn/sliding_window.h b/vcs-svn/sliding_window.h
deleted file mode 100644
index b43a825cba..0000000000
--- a/vcs-svn/sliding_window.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef SLIDING_WINDOW_H_
-#define SLIDING_WINDOW_H_
-
-#include "strbuf.h"
-
-struct sliding_view {
-	struct line_buffer *file;
-	off_t off;
-	size_t width;
-	off_t max_off;	/* -1 means unlimited */
-	struct strbuf buf;
-};
-
-#define SLIDING_VIEW_INIT(input, len)	{ (input), 0, 0, (len), STRBUF_INIT }
-
-extern int move_window(struct sliding_view *view, off_t off, size_t width);
-
-#endif
diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c
deleted file mode 100644
index 75c753162a..0000000000
--- a/vcs-svn/svndiff.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "git-compat-util.h"
-#include "sliding_window.h"
-#include "line_buffer.h"
-#include "svndiff.h"
-
-/*
- * svndiff0 applier
- *
- * See http://svn.apache.org/repos/asf/subversion/trunk/notes/svndiff.
- *
- * svndiff0 ::= 'SVN\0' window*
- * window ::= int int int int int instructions inline_data;
- * instructions ::= instruction*;
- * instruction ::= view_selector int int
- *   | copyfrom_data int
- *   | packed_view_selector int
- *   | packed_copyfrom_data
- *   ;
- * view_selector ::= copyfrom_source
- *   | copyfrom_target
- *   ;
- * copyfrom_source ::= # binary 00 000000;
- * copyfrom_target ::= # binary 01 000000;
- * copyfrom_data ::= # binary 10 000000;
- * packed_view_selector ::= # view_selector OR-ed with 6 bit value;
- * packed_copyfrom_data ::= # copyfrom_data OR-ed with 6 bit value;
- * int ::= highdigit* lowdigit;
- * highdigit ::= # binary 1000 0000 OR-ed with 7 bit value;
- * lowdigit ::= # 7 bit value;
- */
-
-#define INSN_MASK	0xc0
-#define INSN_COPYFROM_SOURCE	0x00
-#define INSN_COPYFROM_TARGET	0x40
-#define INSN_COPYFROM_DATA	0x80
-#define OPERAND_MASK	0x3f
-
-#define VLI_CONTINUE	0x80
-#define VLI_DIGIT_MASK	0x7f
-#define VLI_BITS_PER_DIGIT 7
-
-struct window {
-	struct sliding_view *in;
-	struct strbuf out;
-	struct strbuf instructions;
-	struct strbuf data;
-};
-
-#define WINDOW_INIT(w)	{ (w), STRBUF_INIT, STRBUF_INIT, STRBUF_INIT }
-
-static void window_release(struct window *ctx)
-{
-	strbuf_release(&ctx->out);
-	strbuf_release(&ctx->instructions);
-	strbuf_release(&ctx->data);
-}
-
-static int write_strbuf(struct strbuf *sb, FILE *out)
-{
-	if (fwrite(sb->buf, 1, sb->len, out) == sb->len)	/* Success. */
-		return 0;
-	return error_errno("cannot write delta postimage");
-}
-
-static int error_short_read(struct line_buffer *input)
-{
-	if (buffer_ferror(input))
-		return error_errno("error reading delta");
-	return error("invalid delta: unexpected end of file");
-}
-
-static int read_chunk(struct line_buffer *delta, off_t *delta_len,
-		      struct strbuf *buf, size_t len)
-{
-	assert(*delta_len >= 0);
-	strbuf_reset(buf);
-	if (len > (uintmax_t) *delta_len ||
-	    buffer_read_binary(delta, buf, len) != len)
-		return error_short_read(delta);
-	*delta_len -= buf->len;
-	return 0;
-}
-
-static int read_magic(struct line_buffer *in, off_t *len)
-{
-	static const char magic[] = {'S', 'V', 'N', '\0'};
-	struct strbuf sb = STRBUF_INIT;
-
-	if (read_chunk(in, len, &sb, sizeof(magic))) {
-		strbuf_release(&sb);
-		return -1;
-	}
-	if (memcmp(sb.buf, magic, sizeof(magic))) {
-		strbuf_release(&sb);
-		return error("invalid delta: unrecognized file type");
-	}
-	strbuf_release(&sb);
-	return 0;
-}
-
-static int read_int(struct line_buffer *in, uintmax_t *result, off_t *len)
-{
-	uintmax_t rv = 0;
-	off_t sz;
-	for (sz = *len; sz; sz--) {
-		const int ch = buffer_read_char(in);
-		if (ch == EOF)
-			break;
-
-		rv <<= VLI_BITS_PER_DIGIT;
-		rv += (ch & VLI_DIGIT_MASK);
-		if (ch & VLI_CONTINUE)
-			continue;
-
-		*result = rv;
-		*len = sz - 1;
-		return 0;
-	}
-	return error_short_read(in);
-}
-
-static int parse_int(const char **buf, size_t *result, const char *end)
-{
-	size_t rv = 0;
-	const char *pos;
-	for (pos = *buf; pos != end; pos++) {
-		unsigned char ch = *pos;
-
-		rv <<= VLI_BITS_PER_DIGIT;
-		rv += (ch & VLI_DIGIT_MASK);
-		if (ch & VLI_CONTINUE)
-			continue;
-
-		*result = rv;
-		*buf = pos + 1;
-		return 0;
-	}
-	return error("invalid delta: unexpected end of instructions section");
-}
-
-static int read_offset(struct line_buffer *in, off_t *result, off_t *len)
-{
-	uintmax_t val;
-	if (read_int(in, &val, len))
-		return -1;
-	if (val > maximum_signed_value_of_type(off_t))
-		return error("unrepresentable offset in delta: %"PRIuMAX"", val);
-	*result = val;
-	return 0;
-}
-
-static int read_length(struct line_buffer *in, size_t *result, off_t *len)
-{
-	uintmax_t val;
-	if (read_int(in, &val, len))
-		return -1;
-	if (val > SIZE_MAX)
-		return error("unrepresentable length in delta: %"PRIuMAX"", val);
-	*result = val;
-	return 0;
-}
-
-static int copyfrom_source(struct window *ctx, const char **instructions,
-			   size_t nbytes, const char *insns_end)
-{
-	size_t offset;
-	if (parse_int(instructions, &offset, insns_end))
-		return -1;
-	if (unsigned_add_overflows(offset, nbytes) ||
-	    offset + nbytes > ctx->in->width)
-		return error("invalid delta: copies source data outside view");
-	strbuf_add(&ctx->out, ctx->in->buf.buf + offset, nbytes);
-	return 0;
-}
-
-static int copyfrom_target(struct window *ctx, const char **instructions,
-			   size_t nbytes, const char *instructions_end)
-{
-	size_t offset;
-	if (parse_int(instructions, &offset, instructions_end))
-		return -1;
-	if (offset >= ctx->out.len)
-		return error("invalid delta: copies from the future");
-	for (; nbytes > 0; nbytes--)
-		strbuf_addch(&ctx->out, ctx->out.buf[offset++]);
-	return 0;
-}
-
-static int copyfrom_data(struct window *ctx, size_t *data_pos, size_t nbytes)
-{
-	const size_t pos = *data_pos;
-	if (unsigned_add_overflows(pos, nbytes) ||
-	    pos + nbytes > ctx->data.len)
-		return error("invalid delta: copies unavailable inline data");
-	strbuf_add(&ctx->out, ctx->data.buf + pos, nbytes);
-	*data_pos += nbytes;
-	return 0;
-}
-
-static int parse_first_operand(const char **buf, size_t *out, const char *end)
-{
-	size_t result = (unsigned char) *(*buf)++ & OPERAND_MASK;
-	if (result) {	/* immediate operand */
-		*out = result;
-		return 0;
-	}
-	return parse_int(buf, out, end);
-}
-
-static int execute_one_instruction(struct window *ctx,
-				const char **instructions, size_t *data_pos)
-{
-	unsigned int instruction;
-	const char *insns_end = ctx->instructions.buf + ctx->instructions.len;
-	size_t nbytes;
-	assert(ctx);
-	assert(instructions && *instructions);
-	assert(data_pos);
-
-	instruction = (unsigned char) **instructions;
-	if (parse_first_operand(instructions, &nbytes, insns_end))
-		return -1;
-	switch (instruction & INSN_MASK) {
-	case INSN_COPYFROM_SOURCE:
-		return copyfrom_source(ctx, instructions, nbytes, insns_end);
-	case INSN_COPYFROM_TARGET:
-		return copyfrom_target(ctx, instructions, nbytes, insns_end);
-	case INSN_COPYFROM_DATA:
-		return copyfrom_data(ctx, data_pos, nbytes);
-	default:
-		return error("invalid delta: unrecognized instruction");
-	}
-}
-
-static int apply_window_in_core(struct window *ctx)
-{
-	const char *instructions;
-	size_t data_pos = 0;
-
-	/*
-	 * Fill ctx->out.buf using data from the source, target,
-	 * and inline data views.
-	 */
-	for (instructions = ctx->instructions.buf;
-	     instructions != ctx->instructions.buf + ctx->instructions.len;
-	     )
-		if (execute_one_instruction(ctx, &instructions, &data_pos))
-			return -1;
-	if (data_pos != ctx->data.len)
-		return error("invalid delta: does not copy all inline data");
-	return 0;
-}
-
-static int apply_one_window(struct line_buffer *delta, off_t *delta_len,
-			    struct sliding_view *preimage, FILE *out)
-{
-	int rv = -1;
-	struct window ctx = WINDOW_INIT(preimage);
-	size_t out_len;
-	size_t instructions_len;
-	size_t data_len;
-	assert(delta_len);
-
-	/* "source view" offset and length already handled; */
-	if (read_length(delta, &out_len, delta_len) ||
-	    read_length(delta, &instructions_len, delta_len) ||
-	    read_length(delta, &data_len, delta_len) ||
-	    read_chunk(delta, delta_len, &ctx.instructions, instructions_len) ||
-	    read_chunk(delta, delta_len, &ctx.data, data_len))
-		goto error_out;
-	strbuf_grow(&ctx.out, out_len);
-	if (apply_window_in_core(&ctx))
-		goto error_out;
-	if (ctx.out.len != out_len) {
-		rv = error("invalid delta: incorrect postimage length");
-		goto error_out;
-	}
-	if (write_strbuf(&ctx.out, out))
-		goto error_out;
-	rv = 0;
-error_out:
-	window_release(&ctx);
-	return rv;
-}
-
-int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
-			struct sliding_view *preimage, FILE *postimage)
-{
-	assert(delta && preimage && postimage && delta_len >= 0);
-
-	if (read_magic(delta, &delta_len))
-		return -1;
-	while (delta_len) {	/* For each window: */
-		off_t pre_off = -1;
-		size_t pre_len;
-
-		if (read_offset(delta, &pre_off, &delta_len) ||
-		    read_length(delta, &pre_len, &delta_len) ||
-		    move_window(preimage, pre_off, pre_len) ||
-		    apply_one_window(delta, &delta_len, preimage, postimage))
-			return -1;
-	}
-	return 0;
-}
diff --git a/vcs-svn/svndiff.h b/vcs-svn/svndiff.h
deleted file mode 100644
index 74eb464bab..0000000000
--- a/vcs-svn/svndiff.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SVNDIFF_H_
-#define SVNDIFF_H_
-
-struct line_buffer;
-struct sliding_view;
-
-extern int svndiff0_apply(struct line_buffer *delta, off_t delta_len,
-		struct sliding_view *preimage, FILE *postimage);
-
-#endif
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
deleted file mode 100644
index 08d136b8cc..0000000000
--- a/vcs-svn/svndump.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Parse and rearrange a svnadmin dump.
- * Create the dump with:
- * svnadmin dump --incremental -r<startrev>:<endrev> <repository> >outfile
- *
- * Licensed under a two-clause BSD-style license.
- * See LICENSE for details.
- */
-
-#include "cache.h"
-#include "fast_export.h"
-#include "line_buffer.h"
-#include "strbuf.h"
-#include "svndump.h"
-
-/*
- * Compare start of string to literal of equal length;
- * must be guarded by length test.
- */
-#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
-
-#define REPORT_FILENO 3
-
-#define NODEACT_REPLACE 4
-#define NODEACT_DELETE 3
-#define NODEACT_ADD 2
-#define NODEACT_CHANGE 1
-#define NODEACT_UNKNOWN 0
-
-/* States: */
-#define DUMP_CTX 0	/* dump metadata */
-#define REV_CTX  1	/* revision metadata */
-#define NODE_CTX 2	/* node metadata */
-#define INTERNODE_CTX 3	/* between nodes */
-
-#define DATE_RFC2822_LEN 31
-
-static struct line_buffer input = LINE_BUFFER_INIT;
-
-static struct {
-	uint32_t action, srcRev, type;
-	off_t prop_length, text_length;
-	struct strbuf src, dst;
-	uint32_t text_delta, prop_delta;
-} node_ctx;
-
-static struct {
-	uint32_t revision;
-	timestamp_t timestamp;
-	struct strbuf log, author, note;
-} rev_ctx;
-
-static struct {
-	uint32_t version;
-	struct strbuf uuid, url;
-} dump_ctx;
-
-static void reset_node_ctx(char *fname)
-{
-	node_ctx.type = 0;
-	node_ctx.action = NODEACT_UNKNOWN;
-	node_ctx.prop_length = -1;
-	node_ctx.text_length = -1;
-	strbuf_reset(&node_ctx.src);
-	node_ctx.srcRev = 0;
-	strbuf_reset(&node_ctx.dst);
-	if (fname)
-		strbuf_addstr(&node_ctx.dst, fname);
-	node_ctx.text_delta = 0;
-	node_ctx.prop_delta = 0;
-}
-
-static void reset_rev_ctx(uint32_t revision)
-{
-	rev_ctx.revision = revision;
-	rev_ctx.timestamp = 0;
-	strbuf_reset(&rev_ctx.log);
-	strbuf_reset(&rev_ctx.author);
-	strbuf_reset(&rev_ctx.note);
-}
-
-static void reset_dump_ctx(const char *url)
-{
-	strbuf_reset(&dump_ctx.url);
-	if (url)
-		strbuf_addstr(&dump_ctx.url, url);
-	dump_ctx.version = 1;
-	strbuf_reset(&dump_ctx.uuid);
-}
-
-static void handle_property(const struct strbuf *key_buf,
-				struct strbuf *val,
-				uint32_t *type_set)
-{
-	const char *key = key_buf->buf;
-	size_t keylen = key_buf->len;
-
-	switch (keylen + 1) {
-	case sizeof("svn:log"):
-		if (constcmp(key, "svn:log"))
-			break;
-		if (!val)
-			die("invalid dump: unsets svn:log");
-		strbuf_swap(&rev_ctx.log, val);
-		break;
-	case sizeof("svn:author"):
-		if (constcmp(key, "svn:author"))
-			break;
-		if (!val)
-			strbuf_reset(&rev_ctx.author);
-		else
-			strbuf_swap(&rev_ctx.author, val);
-		break;
-	case sizeof("svn:date"):
-		if (constcmp(key, "svn:date"))
-			break;
-		if (!val)
-			die("invalid dump: unsets svn:date");
-		if (parse_date_basic(val->buf, &rev_ctx.timestamp, NULL))
-			warning("invalid timestamp: %s", val->buf);
-		break;
-	case sizeof("svn:executable"):
-	case sizeof("svn:special"):
-		if (keylen == strlen("svn:executable") &&
-		    constcmp(key, "svn:executable"))
-			break;
-		if (keylen == strlen("svn:special") &&
-		    constcmp(key, "svn:special"))
-			break;
-		if (*type_set) {
-			if (!val)
-				return;
-			die("invalid dump: sets type twice");
-		}
-		if (!val) {
-			node_ctx.type = S_IFREG | 0644;
-			return;
-		}
-		*type_set = 1;
-		node_ctx.type = keylen == strlen("svn:executable") ?
-				(S_IFREG | 0755) :
-				S_IFLNK;
-	}
-}
-
-static void die_short_read(void)
-{
-	if (buffer_ferror(&input))
-		die_errno("error reading dump file");
-	die("invalid dump: unexpected end of file");
-}
-
-static void read_props(void)
-{
-	static struct strbuf key = STRBUF_INIT;
-	static struct strbuf val = STRBUF_INIT;
-	const char *t;
-	/*
-	 * NEEDSWORK: to support simple mode changes like
-	 *	K 11
-	 *	svn:special
-	 *	V 1
-	 *	*
-	 *	D 14
-	 *	svn:executable
-	 * we keep track of whether a mode has been set and reset to
-	 * plain file only if not.  We should be keeping track of the
-	 * symlink and executable bits separately instead.
-	 */
-	uint32_t type_set = 0;
-	while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) {
-		uint32_t len;
-		const char type = t[0];
-		int ch;
-
-		if (!type || t[1] != ' ')
-			die("invalid property line: %s", t);
-		len = atoi(&t[2]);
-		strbuf_reset(&val);
-		buffer_read_binary(&input, &val, len);
-		if (val.len < len)
-			die_short_read();
-
-		/* Discard trailing newline. */
-		ch = buffer_read_char(&input);
-		if (ch == EOF)
-			die_short_read();
-		if (ch != '\n')
-			die("invalid dump: expected newline after %s", val.buf);
-
-		switch (type) {
-		case 'K':
-			strbuf_swap(&key, &val);
-			continue;
-		case 'D':
-			handle_property(&val, NULL, &type_set);
-			continue;
-		case 'V':
-			handle_property(&key, &val, &type_set);
-			strbuf_reset(&key);
-			continue;
-		default:
-			die("invalid property line: %s", t);
-		}
-	}
-}
-
-static void handle_node(void)
-{
-	const uint32_t type = node_ctx.type;
-	const int have_props = node_ctx.prop_length != -1;
-	const int have_text = node_ctx.text_length != -1;
-	/*
-	 * Old text for this node:
-	 *  NULL	- directory or bug
-	 *  empty_blob	- empty
-	 *  "<dataref>"	- data retrievable from fast-import
-	 */
-	static const char *const empty_blob = "::empty::";
-	const char *old_data = NULL;
-	uint32_t old_mode = S_IFREG | 0644;
-
-	if (node_ctx.action == NODEACT_DELETE) {
-		if (have_text || have_props || node_ctx.srcRev)
-			die("invalid dump: deletion node has "
-				"copyfrom info, text, or properties");
-		fast_export_delete(node_ctx.dst.buf);
-		return;
-	}
-	if (node_ctx.action == NODEACT_REPLACE) {
-		fast_export_delete(node_ctx.dst.buf);
-		node_ctx.action = NODEACT_ADD;
-	}
-	if (node_ctx.srcRev) {
-		fast_export_copy(node_ctx.srcRev, node_ctx.src.buf, node_ctx.dst.buf);
-		if (node_ctx.action == NODEACT_ADD)
-			node_ctx.action = NODEACT_CHANGE;
-	}
-	if (have_text && type == S_IFDIR)
-		die("invalid dump: directories cannot have text attached");
-
-	/*
-	 * Find old content (old_data) and decide on the new mode.
-	 */
-	if (node_ctx.action == NODEACT_CHANGE && !*node_ctx.dst.buf) {
-		if (type != S_IFDIR)
-			die("invalid dump: root of tree is not a regular file");
-		old_data = NULL;
-	} else if (node_ctx.action == NODEACT_CHANGE) {
-		uint32_t mode;
-		old_data = fast_export_read_path(node_ctx.dst.buf, &mode);
-		if (mode == S_IFDIR && type != S_IFDIR)
-			die("invalid dump: cannot modify a directory into a file");
-		if (mode != S_IFDIR && type == S_IFDIR)
-			die("invalid dump: cannot modify a file into a directory");
-		node_ctx.type = mode;
-		old_mode = mode;
-	} else if (node_ctx.action == NODEACT_ADD) {
-		if (type == S_IFDIR)
-			old_data = NULL;
-		else if (have_text)
-			old_data = empty_blob;
-		else
-			die("invalid dump: adds node without text");
-	} else {
-		die("invalid dump: Node-path block lacks Node-action");
-	}
-
-	/*
-	 * Adjust mode to reflect properties.
-	 */
-	if (have_props) {
-		if (!node_ctx.prop_delta)
-			node_ctx.type = type;
-		if (node_ctx.prop_length)
-			read_props();
-	}
-
-	/*
-	 * Save the result.
-	 */
-	if (type == S_IFDIR)	/* directories are not tracked. */
-		return;
-	assert(old_data);
-	if (old_data == empty_blob)
-		/* For the fast_export_* functions, NULL means empty. */
-		old_data = NULL;
-	if (!have_text) {
-		fast_export_modify(node_ctx.dst.buf, node_ctx.type, old_data);
-		return;
-	}
-	if (!node_ctx.text_delta) {
-		fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline");
-		fast_export_data(node_ctx.type, node_ctx.text_length, &input);
-		return;
-	}
-	fast_export_modify(node_ctx.dst.buf, node_ctx.type, "inline");
-	fast_export_blob_delta(node_ctx.type, old_mode, old_data,
-				node_ctx.text_length, &input);
-}
-
-static void begin_revision(const char *remote_ref)
-{
-	if (!rev_ctx.revision)	/* revision 0 gets no git commit. */
-		return;
-	fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
-		&rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-		rev_ctx.timestamp, remote_ref);
-}
-
-static void end_revision(const char *note_ref)
-{
-	struct strbuf mark = STRBUF_INIT;
-	if (rev_ctx.revision) {
-		fast_export_end_commit(rev_ctx.revision);
-		fast_export_begin_note(rev_ctx.revision, "remote-svn",
-				"Note created by remote-svn.", rev_ctx.timestamp, note_ref);
-		strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
-		fast_export_note(mark.buf, "inline");
-		fast_export_buf_to_data(&rev_ctx.note);
-		strbuf_release(&mark);
-	}
-}
-
-void svndump_read(const char *url, const char *local_ref, const char *notes_ref)
-{
-	char *val;
-	char *t;
-	uint32_t active_ctx = DUMP_CTX;
-	uint32_t len;
-
-	reset_dump_ctx(url);
-	while ((t = buffer_read_line(&input))) {
-		val = strchr(t, ':');
-		if (!val)
-			continue;
-		val++;
-		if (*val != ' ')
-			continue;
-		val++;
-
-		/* strlen(key) + 1 */
-		switch (val - t - 1) {
-		case sizeof("SVN-fs-dump-format-version"):
-			if (constcmp(t, "SVN-fs-dump-format-version"))
-				continue;
-			dump_ctx.version = atoi(val);
-			if (dump_ctx.version > 3)
-				die("expected svn dump format version <= 3, found %"PRIu32,
-				    dump_ctx.version);
-			break;
-		case sizeof("UUID"):
-			if (constcmp(t, "UUID"))
-				continue;
-			strbuf_reset(&dump_ctx.uuid);
-			strbuf_addstr(&dump_ctx.uuid, val);
-			break;
-		case sizeof("Revision-number"):
-			if (constcmp(t, "Revision-number"))
-				continue;
-			if (active_ctx == NODE_CTX)
-				handle_node();
-			if (active_ctx == REV_CTX)
-				begin_revision(local_ref);
-			if (active_ctx != DUMP_CTX)
-				end_revision(notes_ref);
-			active_ctx = REV_CTX;
-			reset_rev_ctx(atoi(val));
-			strbuf_addf(&rev_ctx.note, "%s\n", t);
-			break;
-		case sizeof("Node-path"):
-			if (constcmp(t, "Node-"))
-				continue;
-			if (!constcmp(t + strlen("Node-"), "path")) {
-				if (active_ctx == NODE_CTX)
-					handle_node();
-				if (active_ctx == REV_CTX)
-					begin_revision(local_ref);
-				active_ctx = NODE_CTX;
-				reset_node_ctx(val);
-				strbuf_addf(&rev_ctx.note, "%s\n", t);
-				break;
-			}
-			if (constcmp(t + strlen("Node-"), "kind"))
-				continue;
-			strbuf_addf(&rev_ctx.note, "%s\n", t);
-			if (!strcmp(val, "dir"))
-				node_ctx.type = S_IFDIR;
-			else if (!strcmp(val, "file"))
-				node_ctx.type = S_IFREG | 0644;
-			else
-				fprintf(stderr, "Unknown node-kind: %s\n", val);
-			break;
-		case sizeof("Node-action"):
-			if (constcmp(t, "Node-action"))
-				continue;
-			strbuf_addf(&rev_ctx.note, "%s\n", t);
-			if (!strcmp(val, "delete")) {
-				node_ctx.action = NODEACT_DELETE;
-			} else if (!strcmp(val, "add")) {
-				node_ctx.action = NODEACT_ADD;
-			} else if (!strcmp(val, "change")) {
-				node_ctx.action = NODEACT_CHANGE;
-			} else if (!strcmp(val, "replace")) {
-				node_ctx.action = NODEACT_REPLACE;
-			} else {
-				fprintf(stderr, "Unknown node-action: %s\n", val);
-				node_ctx.action = NODEACT_UNKNOWN;
-			}
-			break;
-		case sizeof("Node-copyfrom-path"):
-			if (constcmp(t, "Node-copyfrom-path"))
-				continue;
-			strbuf_reset(&node_ctx.src);
-			strbuf_addstr(&node_ctx.src, val);
-			strbuf_addf(&rev_ctx.note, "%s\n", t);
-			break;
-		case sizeof("Node-copyfrom-rev"):
-			if (constcmp(t, "Node-copyfrom-rev"))
-				continue;
-			node_ctx.srcRev = atoi(val);
-			strbuf_addf(&rev_ctx.note, "%s\n", t);
-			break;
-		case sizeof("Text-content-length"):
-			if (constcmp(t, "Text") && constcmp(t, "Prop"))
-				continue;
-			if (constcmp(t + 4, "-content-length"))
-				continue;
-			{
-				char *end;
-				uintmax_t len;
-
-				len = strtoumax(val, &end, 10);
-				if (!isdigit(*val) || *end)
-					die("invalid dump: non-numeric length %s", val);
-				if (len > maximum_signed_value_of_type(off_t))
-					die("unrepresentable length in dump: %s", val);
-
-				if (*t == 'T')
-					node_ctx.text_length = (off_t) len;
-				else
-					node_ctx.prop_length = (off_t) len;
-				break;
-			}
-		case sizeof("Text-delta"):
-			if (!constcmp(t, "Text-delta")) {
-				node_ctx.text_delta = !strcmp(val, "true");
-				break;
-			}
-			if (constcmp(t, "Prop-delta"))
-				continue;
-			node_ctx.prop_delta = !strcmp(val, "true");
-			break;
-		case sizeof("Content-length"):
-			if (constcmp(t, "Content-length"))
-				continue;
-			len = atoi(val);
-			t = buffer_read_line(&input);
-			if (!t)
-				die_short_read();
-			if (*t)
-				die("invalid dump: expected blank line after content length header");
-			if (active_ctx == REV_CTX) {
-				read_props();
-			} else if (active_ctx == NODE_CTX) {
-				handle_node();
-				active_ctx = INTERNODE_CTX;
-			} else {
-				fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
-				if (buffer_skip_bytes(&input, len) != len)
-					die_short_read();
-			}
-		}
-	}
-	if (buffer_ferror(&input))
-		die_short_read();
-	if (active_ctx == NODE_CTX)
-		handle_node();
-	if (active_ctx == REV_CTX)
-		begin_revision(local_ref);
-	if (active_ctx != DUMP_CTX)
-		end_revision(notes_ref);
-}
-
-static void init(int report_fd)
-{
-	fast_export_init(report_fd);
-	strbuf_init(&dump_ctx.uuid, 4096);
-	strbuf_init(&dump_ctx.url, 4096);
-	strbuf_init(&rev_ctx.log, 4096);
-	strbuf_init(&rev_ctx.author, 4096);
-	strbuf_init(&rev_ctx.note, 4096);
-	strbuf_init(&node_ctx.src, 4096);
-	strbuf_init(&node_ctx.dst, 4096);
-	reset_dump_ctx(NULL);
-	reset_rev_ctx(0);
-	reset_node_ctx(NULL);
-	return;
-}
-
-int svndump_init(const char *filename)
-{
-	if (buffer_init(&input, filename))
-		return error_errno("cannot open %s", filename ? filename : "NULL");
-	init(REPORT_FILENO);
-	return 0;
-}
-
-int svndump_init_fd(int in_fd, int back_fd)
-{
-	if(buffer_fdinit(&input, xdup(in_fd)))
-		return error_errno("cannot open fd %d", in_fd);
-	init(xdup(back_fd));
-	return 0;
-}
-
-void svndump_deinit(void)
-{
-	fast_export_deinit();
-	reset_dump_ctx(NULL);
-	reset_rev_ctx(0);
-	reset_node_ctx(NULL);
-	strbuf_release(&rev_ctx.log);
-	strbuf_release(&rev_ctx.author);
-	strbuf_release(&rev_ctx.note);
-	strbuf_release(&node_ctx.src);
-	strbuf_release(&node_ctx.dst);
-	if (buffer_deinit(&input))
-		fprintf(stderr, "Input error\n");
-	if (ferror(stdout))
-		fprintf(stderr, "Output error\n");
-}
-
-void svndump_reset(void)
-{
-	strbuf_release(&dump_ctx.uuid);
-	strbuf_release(&dump_ctx.url);
-	strbuf_release(&rev_ctx.log);
-	strbuf_release(&rev_ctx.author);
-}
diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h
deleted file mode 100644
index b8eb12954e..0000000000
--- a/vcs-svn/svndump.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SVNDUMP_H_
-#define SVNDUMP_H_
-
-int svndump_init(const char *filename);
-int svndump_init_fd(int in_fd, int back_fd);
-void svndump_read(const char *url, const char *local_ref, const char *notes_ref);
-void svndump_deinit(void);
-void svndump_reset(void);
-
-#endif
-- 
2.18.0.1205.g3878b1e64a

^ permalink raw reply related	[relevance 1%]

* Re: [PATCH] l10n: de.po: translate 108 new messages
  2018-07-19 17:15  1% [PATCH] l10n: de.po: translate 108 new messages Ralf Thielow
@ 2018-07-23 19:12  0% ` Matthias Rüster
  0 siblings, 0 replies; 200+ results
From: Matthias Rüster @ 2018-07-23 19:12 UTC (permalink / raw)
  To: Ralf Thielow, Phillip Szelat; +Cc: git

Acked-by: Matthias Rüster <matthias.ruester@gmail.com>

Thanks!



Am 19.07.2018 um 19:15 schrieb Ralf Thielow:
> Translate 108 new messages came from git.pot update in 9b7388a85 (l10n:
> git.pot: v2.18.0 round 1 (108 new, 14 removed)).
> 
> Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
> ---
>   po/de.po | 373 +++++++++++++++++++++++++++++--------------------------
>   1 file changed, 194 insertions(+), 179 deletions(-)
> 
> diff --git a/po/de.po b/po/de.po
> index bdc5830e1..47986814c 100644
> --- a/po/de.po
> +++ b/po/de.po
> @@ -10,25 +10,25 @@ msgstr ""
>   "POT-Creation-Date: 2018-05-31 23:32+0800\n"
>   "PO-Revision-Date: 2016-11-28 18:10+0100\n"
>   "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
>   "Language-Team: German <>\n"
>   "Language: de\n"
>   "MIME-Version: 1.0\n"
>   "Content-Type: text/plain; charset=UTF-8\n"
>   "Content-Transfer-Encoding: 8bit\n"
>   "Plural-Forms: nplurals=2; plural=(n!=1);\n"
>   
>   #: advice.c:92
> -#, fuzzy, c-format
> +#, c-format
>   msgid "%shint: %.*s%s\n"
> -msgstr "Hinweis: %.*s\n"
> +msgstr "%sHinweis: %.*s%s\n"
>   
>   #: advice.c:137
>   msgid "Cherry-picking is not possible because you have unmerged files."
>   msgstr ""
>   "Cherry-Picken ist nicht möglich, weil Sie nicht zusammengeführte Dateien "
>   "haben."
>   
>   #: advice.c:139
>   msgid "Committing is not possible because you have unmerged files."
>   msgstr ""
>   "Committen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
> @@ -1284,44 +1284,52 @@ msgstr "%s %s ist kein Commit!"
>   #: commit.c:182
>   msgid ""
>   "Support for <GIT_DIR>/info/grafts is deprecated\n"
>   "and will be removed in a future Git version.\n"
>   "\n"
>   "Please use \"git replace --convert-graft-file\"\n"
>   "to convert the grafts into replace refs.\n"
>   "\n"
>   "Turn this message off by running\n"
>   "\"git config advice.graftFileDeprecated false\""
>   msgstr ""
> +"Die Unterstützung für <GIT_DIR>/info/grafts ist veraltet\n"
> +"und wird in zukünftigen Git Versionen entfernt.\n"
> +"\n"
> +"Bitte benutzen Sie \"git replace --convert-graft-file\"\n"
> +"zum Konvertieren der künstlichen Vorgänger (\"grafts\")\n"
> +"in ersetzende Referenzen.<\n"
> +"\n"
> +"Sie können diese Meldung unterdrücken, indem Sie\n"
> +"\"git config advice.graftFileDeprecated false\" ausführen."
>   
>   #: commit.c:1537
>   msgid ""
>   "Warning: commit message did not conform to UTF-8.\n"
>   "You may want to amend it after fixing the message, or set the config\n"
>   "variable i18n.commitencoding to the encoding your project uses.\n"
>   msgstr ""
>   "Warnung: Die Commit-Beschreibung ist nicht UTF-8 konform.\n"
>   "Sie können das nachbessern, nachdem Sie die Beschreibung korrigiert haben,\n"
>   "oder Sie setzen die Konfigurationsvariable i18n.commitencoding auf das "
>   "Encoding,\n"
>   "welches von ihrem Projekt verwendet wird.\n"
>   
>   #: commit-graph.c:669
>   #, c-format
>   msgid "the commit graph format cannot write %d commits"
> -msgstr ""
> +msgstr "Das Commit-Graph Format kann nicht %d Commits schreiben."
>   
>   #: commit-graph.c:696
> -#, fuzzy
>   msgid "too many commits to write graph"
> -msgstr "nur Commits anzeigen, die sich nicht im ersten Branch befinden"
> +msgstr "Zu viele Commits zum Schreiben des Graphen."
>   
>   #: commit-graph.c:707 builtin/init-db.c:516 builtin/init-db.c:521
>   #, c-format
>   msgid "cannot mkdir %s"
>   msgstr "kann Verzeichnis %s nicht erstellen"
>   
>   #: compat/obstack.c:405 compat/obstack.c:407
>   msgid "memory exhausted"
>   msgstr "Speicher verbraucht"
>   
>   #: config.c:187
> @@ -1554,56 +1562,61 @@ msgstr "LF würde in %s durch CRLF ersetzt werden."
>   msgid ""
>   "LF will be replaced by CRLF in %s.\n"
>   "The file will have its original line endings in your working directory."
>   msgstr ""
>   "LF wird in %s durch CRLF ersetzt.\n"
>   "Die Datei wird ihre ursprünglichen Zeilenenden im Arbeitsverzeichnis "
>   "behalten."
>   
>   #: convert.c:279
>   #, c-format
>   msgid "BOM is prohibited in '%s' if encoded as %s"
> -msgstr ""
> +msgstr "BOM ist in '%s' unzulässig, wenn als %s codiert."
>   
>   #: convert.c:286
>   #, c-format
>   msgid ""
>   "The file '%s' contains a byte order mark (BOM). Please use UTF-%s as working-"
>   "tree-encoding."
>   msgstr ""
> +"Die Datei '%s' enthält ein Byte-Order-Mark (BOM). Bitte benutzen Sie UTF-%s\n"
> +"als Codierung im Arbeitsverzeichnis."
>   
>   #: convert.c:304
>   #, c-format
>   msgid "BOM is required in '%s' if encoded as %s"
> -msgstr ""
> +msgstr "BOM ist erforderlich in '%s', wenn als %s codiert."
>   
>   #: convert.c:306
>   #, c-format
>   msgid ""
>   "The file '%s' is missing a byte order mark (BOM). Please use UTF-%sBE or UTF-"
>   "%sLE (depending on the byte order) as working-tree-encoding."
>   msgstr ""
> +"Der Datei '%s' fehlt ein Byte-Order-Mark (BOM). Bitte benutzen Sie UTF-%sBE\n"
> +"oder UTF-%sLE (abhängig von der Byte-Reihenfolge) als Codierung im\n"
> +"Arbeitsverzeichnis."
>   
>   #: convert.c:424
> -#, fuzzy, c-format
> +#, c-format
>   msgid "failed to encode '%s' from %s to %s"
> -msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
> +msgstr "Fehler beim Codieren von '%s' von %s nach %s."
>   
>   #: convert.c:467
>   #, c-format
>   msgid "encoding '%s' from %s to %s and back is not the same"
> -msgstr ""
> +msgstr "Die Codierung '%s' von %s nach %s und zurück ist nicht dasselbe."
>   
>   #: convert.c:1225
>   msgid "true/false are no valid working-tree-encodings"
> -msgstr ""
> +msgstr "true/false sind keine gültigen Codierungen im Arbeitsverzeichnis."
>   
>   #: date.c:116
>   msgid "in the future"
>   msgstr "in der Zukunft"
>   
>   #: date.c:122
>   #, c-format
>   msgid "%<PRIuMAX> second ago"
>   msgid_plural "%<PRIuMAX> seconds ago"
>   msgstr[0] "vor %<PRIuMAX> Sekunde"
>   msgstr[1] "vor %<PRIuMAX> Sekunden"
> @@ -1970,25 +1983,24 @@ msgid "Server does not support --deepen"
>   msgstr "Server unterstützt kein --deepen"
>   
>   #: fetch-pack.c:1065
>   msgid "no common commits"
>   msgstr "keine gemeinsamen Commits"
>   
>   #: fetch-pack.c:1077 fetch-pack.c:1414
>   msgid "git fetch-pack: fetch failed."
>   msgstr "git fetch-pack: Abholen fehlgeschlagen."
>   
>   #: fetch-pack.c:1199
> -#, fuzzy
>   msgid "Server does not support shallow requests"
> -msgstr "Server unterstützt keine shallow-Clients"
> +msgstr "Server unterstützt keine shallow-Anfragen."
>   
>   #: fetch-pack.c:1584
>   msgid "no matching remote head"
>   msgstr "kein übereinstimmender Remote-Branch"
>   
>   #: fetch-pack.c:1610
>   #, c-format
>   msgid "no such remote ref %s"
>   msgstr "keine solche Remote-Referenz %s"
>   
>   #: fetch-pack.c:1613
> @@ -2212,30 +2224,32 @@ msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
>   
>   #: merge.c:136 builtin/am.c:1946 builtin/am.c:1980 builtin/checkout.c:378
>   #: builtin/checkout.c:606 builtin/clone.c:761
>   msgid "unable to write new index file"
>   msgstr "Konnte neue Index-Datei nicht schreiben."
>   
>   #: merge-recursive.c:298
>   msgid "(bad commit)\n"
>   msgstr "(ungültiger Commit)\n"
>   
>   #: merge-recursive.c:320
> -#, fuzzy, c-format
> +#, c-format
>   msgid "add_cacheinfo failed for path '%s'; merge aborting."
> -msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen"
> +msgstr "add_cacheinfo für Pfad '%s' fehlgeschlagen; Merge wird abgebrochen."
>   
>   #: merge-recursive.c:328
> -#, fuzzy, c-format
> +#, c-format
>   msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
> -msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen"
> +msgstr ""
> +"add_cacheinfo zur Aktualisierung für Pfad '%s' fehlgeschlagen;\n"
> +"Merge wird abgebrochen."
>   
>   #: merge-recursive.c:410
>   msgid "error building trees"
>   msgstr "Fehler beim Erstellen der \"Tree\"-Objekte"
>   
>   #: merge-recursive.c:881
>   #, c-format
>   msgid "failed to create path '%s'%s"
>   msgstr "Fehler beim Erstellen des Pfades '%s'%s"
>   
>   #: merge-recursive.c:892
> @@ -2270,94 +2284,101 @@ msgstr "Fehler beim Öffnen von '%s': %s"
>   #: merge-recursive.c:994
>   #, c-format
>   msgid "failed to symlink '%s': %s"
>   msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s': %s"
>   
>   #: merge-recursive.c:999
>   #, c-format
>   msgid "do not know what to do with %06o %s '%s'"
>   msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
>   
>   #: merge-recursive.c:1186
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Failed to merge submodule %s (not checked out)"
> -msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
> +msgstr "Fehler beim Merge von Submodul %s (nicht ausgecheckt)."
>   
>   #: merge-recursive.c:1193
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Failed to merge submodule %s (commits not present)"
> -msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
> +msgstr "Fehler beim Merge von Submodul %s (Commits nicht vorhanden)."
>   
>   #: merge-recursive.c:1200
>   #, c-format
>   msgid "Failed to merge submodule %s (commits don't follow merge-base)"
> -msgstr ""
> +msgstr "Fehler beim Merge von Submodul %s (Commits folgen keiner Merge-Basis)"
>   
>   #: merge-recursive.c:1208 merge-recursive.c:1220
>   #, c-format
>   msgid "Fast-forwarding submodule %s to the following commit:"
> -msgstr ""
> +msgstr "Spule Submodul %s zu dem folgenden Commit vor:"
>   
>   #: merge-recursive.c:1211 merge-recursive.c:1223
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Fast-forwarding submodule %s to %s"
> -msgstr "Spule vor zu $sha1"
> +msgstr "Spule Submodul %s vor zu %s"
>   
>   #: merge-recursive.c:1245
>   #, c-format
>   msgid "Failed to merge submodule %s (merge following commits not found)"
> -msgstr ""
> +msgstr "Fehler beim Merge von Submodule %s (dem Merge nachfolgende Commits nicht gefunden)"
>   
>   #: merge-recursive.c:1249
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Failed to merge submodule %s (not fast-forward)"
> -msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
> +msgstr "Fehler beim Merge von Submodul %s (kein Vorspulen)"
>   
>   #: merge-recursive.c:1250
>   msgid "Found a possible merge resolution for the submodule:\n"
> -msgstr ""
> +msgstr "Mögliche Auflösung des Merges für Submodul gefunden:\n"
>   
>   #: merge-recursive.c:1253
>   #, c-format
>   msgid ""
>   "If this is correct simply add it to the index for example\n"
>   "by using:\n"
>   "\n"
>   "  git update-index --cacheinfo 160000 %s \"%s\"\n"
>   "\n"
>   "which will accept this suggestion.\n"
>   msgstr ""
> +"Falls das korrekt ist, fügen Sie es einfach der Staging-Area, zum Beispiel mit:\n"
> +"\n"
> +"  git update-index --cacheinfo 160000 %s \"%s\"\n"
> +"\n"
> +"hinzu, um diesen Vorschlag zu akzeptieren.\n"
>   
>   #: merge-recursive.c:1262
>   #, c-format
>   msgid "Failed to merge submodule %s (multiple merges found)"
> -msgstr ""
> +msgstr "Fehler beim Merge von Submodul %s (mehrere Merges gefunden)"
>   
>   #: merge-recursive.c:1321
>   msgid "Failed to execute internal merge"
>   msgstr "Fehler bei Ausführung des internen Merges"
>   
>   #: merge-recursive.c:1326
>   #, c-format
>   msgid "Unable to add %s to database"
>   msgstr "Konnte %s nicht zur Datenbank hinzufügen"
>   
>   #: merge-recursive.c:1358
>   #, c-format
>   msgid "Auto-merging %s"
>   msgstr "automatischer Merge von %s"
>   
>   #: merge-recursive.c:1423
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
> -msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
> +msgstr ""
> +"Fehler: Verweigere unversionierte Datei bei %s zu verlieren;\n"
> +"schreibe stattdessen nach %s."
>   
>   #: merge-recursive.c:1475
>   #, c-format
>   msgid ""
>   "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
>   "in tree."
>   msgstr ""
>   "KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
>   "im Arbeitsbereich gelassen."
>   
>   #: merge-recursive.c:1480
> @@ -2389,35 +2410,35 @@ msgstr ""
>   
>   #: merge-recursive.c:1526
>   msgid "rename"
>   msgstr "umbenennen"
>   
>   #: merge-recursive.c:1526
>   msgid "renamed"
>   msgstr "umbenannt"
>   
>   #: merge-recursive.c:1580 merge-recursive.c:1736 merge-recursive.c:2368
>   #: merge-recursive.c:3086
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Refusing to lose dirty file at %s"
> -msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
> +msgstr "Verweigere geänderte Datei bei %s zu verlieren."
>   
>   #: merge-recursive.c:1594
>   #, c-format
>   msgid "%s is a directory in %s adding as %s instead"
>   msgstr "%s ist ein Verzeichnis in %s, füge es stattdessen als %s hinzu"
>   
>   #: merge-recursive.c:1599
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Refusing to lose untracked file at %s; adding as %s instead"
> -msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
> +msgstr "Verweigere unversionierte Datei bei %s zu verlieren; füge stattdessen %s hinzu"
>   
>   #: merge-recursive.c:1625
>   #, c-format
>   msgid ""
>   "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
>   "\"->\"%s\" in \"%s\"%s"
>   msgstr ""
>   "KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Branch \"%s\" "
>   "und \"%s\"->\"%s\" in Branch \"%s\"%s"
>   
>   #: merge-recursive.c:1630
> @@ -2429,63 +2450,72 @@ msgstr " (bleibt unaufgelöst)"
>   msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
>   msgstr ""
>   "KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s "
>   "in %s"
>   
>   #: merge-recursive.c:1733
>   #, c-format
>   msgid "Renaming %s to %s and %s to %s instead"
>   msgstr "Benenne stattdessen %s nach %s und %s nach %s um"
>   
>   #: merge-recursive.c:1745
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Refusing to lose untracked file at %s, even though it's in the way."
> -msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
> +msgstr "Verweigere unversionierte Datei bei %s zu verlieren, auch wenn diese im Weg ist."
>   
>   #: merge-recursive.c:1951
>   #, c-format
>   msgid ""
>   "CONFLICT (directory rename split): Unclear where to place %s because "
>   "directory %s was renamed to multiple other directories, with no destination "
>   "getting a majority of the files."
>   msgstr ""
> +"KONFLIKT (Aufteilung Verzeichnisumbenennung): Unklar, wo %s zu platzieren ist,\n"
> +"weil Verzeichnis %s zu mehreren anderen Verzeichnissen umbenannt wurde, wobei\n"
> +"keines dieser Ziele die Mehrheit der Dateien erhielt."
>   
>   #: merge-recursive.c:1983
>   #, c-format
>   msgid ""
>   "CONFLICT (implicit dir rename): Existing file/dir at %s in the way of "
>   "implicit directory rename(s) putting the following path(s) there: %s."
>   msgstr ""
> +"KONFLIKT (implizite Verzeichnisumbenennung): Existierende Datei/Pfad bei %s im\n"
> +"Weg von impliziter Verzeichnisumbenennung, die versucht, einen oder mehrere\n"
> +"Pfade dahin zu setzen: %s."
>   
>   #: merge-recursive.c:1993
>   #, c-format
>   msgid ""
>   "CONFLICT (implicit dir rename): Cannot map more than one path to %s; "
>   "implicit directory renames tried to put these paths there: %s"
>   msgstr ""
> +"KONFLIKT (implizite Verzeichnisumbenennung): Kann nicht mehr als ein Pfad zu\n"
> +"%s mappen; implizite Verzeichnisumbenennungen versuchten diese Pfade dahin\n"
> +"zu setzen: %s"
>   
>   #: merge-recursive.c:2085
> -#, fuzzy, c-format
> +#, c-format
>   msgid ""
>   "CONFLICT (rename/rename): Rename directory %s->%s in %s. Rename directory %s-"
>   ">%s in %s"
>   msgstr ""
> -"KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s "
> -"in %s"
> +"KONFLIKT (umbenennen/umbenennen): Benenne Verzeichnis um %s->%s in %s.\n"
> +"Benenne Verzeichnis um %s->%s in %s"
>   
>   #: merge-recursive.c:2330
>   #, c-format
>   msgid ""
>   "WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
>   "renamed."
> -msgstr ""
> +msgstr "WARNUNG: Vermeide Umbenennung %s -> %s von %s, weil %s selbst umbenannt wurde."
>   
>   #: merge-recursive.c:2736
>   #, c-format
>   msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
>   msgstr ""
>   "KONFLIKT (umbenennen/hinzufügen): Benenne um %s->%s in %s. %s hinzugefügt in "
>   "%s"
>   
>   #: merge-recursive.c:2751
>   #, c-format
>   msgid "Adding merged %s"
> @@ -2682,25 +2712,25 @@ msgstr "      oder: %s"
>   
>   #: parse-options.c:649
>   #, c-format
>   msgid "    %s"
>   msgstr "    %s"
>   
>   #: parse-options.c:688
>   msgid "-NUM"
>   msgstr "-NUM"
>   
>   #: parse-options-cb.c:44
> -#, fuzzy, c-format
> +#, c-format
>   msgid "malformed expiration date '%s'"
> -msgstr "Fehlerhaftes Optionsblatt: '%s'"
> +msgstr "Fehlerhaftes Ablaufdatum '%s'"
>   
>   #: parse-options-cb.c:112
>   #, c-format
>   msgid "malformed object name '%s'"
>   msgstr "fehlerhafter Objekt-Name '%s'"
>   
>   #: path.c:892
>   #, c-format
>   msgid "Could not make %s writable by group"
>   msgstr "Konnte Gruppenschreibrecht für %s nicht setzen."
>   
> @@ -3012,25 +3042,25 @@ msgstr "Format: %%(end) Atom ohne zugehöriges Atom verwendet"
>   #: ref-filter.c:779
>   #, c-format
>   msgid "malformed format string %s"
>   msgstr "Fehlerhafter Formatierungsstring %s"
>   
>   #: ref-filter.c:1387
>   #, c-format
>   msgid "(no branch, rebasing %s)"
>   msgstr "(kein Branch, Rebase von Branch %s im Gange)"
>   
>   #: ref-filter.c:1390
> -#, fuzzy, c-format
> +#, c-format
>   msgid "(no branch, rebasing detached HEAD %s)"
> -msgstr "(kein Branch, Rebase von Branch %s im Gange)"
> +msgstr "(kein Branch, Rebase von losgelöstem HEAD %s)"
>   
>   #: ref-filter.c:1393
>   #, c-format
>   msgid "(no branch, bisect started on %s)"
>   msgstr "(kein Branch, binäre Suche begonnen bei %s)"
>   
>   #. TRANSLATORS: make sure this matches "HEAD
>   #. detached at " in wt-status.c
>   #.
>   #: ref-filter.c:1401
>   #, c-format
> @@ -3283,25 +3313,25 @@ msgstr "die Gegenseite unterstützt keinen atomaren Versand (\"--atomic push\")"
>   
>   #: send-pack.c:440
>   msgid "the receiving end does not support push options"
>   msgstr "die Gegenseite unterstützt keine Push-Optionen"
>   
>   #: sequencer.c:174
>   #, c-format
>   msgid "invalid commit message cleanup mode '%s'"
>   msgstr "Ungültiger \"cleanup\"-Modus '%s' für Commit-Beschreibungen."
>   
>   #: sequencer.c:274
> -#, fuzzy, c-format
> +#, c-format
>   msgid "could not delete '%s'"
> -msgstr "Konnte %s nicht entfernen"
> +msgstr "Konnte '%s' nicht löschen."
>   
>   #: sequencer.c:300
>   msgid "revert"
>   msgstr "Revert"
>   
>   #: sequencer.c:302
>   msgid "cherry-pick"
>   msgstr "Cherry-Pick"
>   
>   #: sequencer.c:304
>   msgid "rebase -i"
> @@ -3414,25 +3444,24 @@ msgstr ""
>   "  git commit --amend %s\n"
>   "\n"
>   "Wenn daraus ein neuer Commit erzeugt werden soll, führen Sie aus:\n"
>   "\n"
>   "  git commit %s\n"
>   "\n"
>   "Im Anschluss führen Sie zum Fortfahren aus:\n"
>   "\n"
>   "  git rebase --continue\n"
>   
>   #: sequencer.c:817
> -#, fuzzy
>   msgid "writing root commit"
> -msgstr "nichts zu committen\n"
> +msgstr "Root-Commit schreiben"
>   
>   #: sequencer.c:1042
>   msgid "'prepare-commit-msg' hook failed"
>   msgstr "'prepare-commit-msg' Hook fehlgeschlagen."
>   
>   #: sequencer.c:1049
>   msgid ""
>   "Your name and email address were configured automatically based\n"
>   "on your username and hostname. Please check that they are accurate.\n"
>   "You can suppress this message by setting them explicitly. Run the\n"
>   "following command and follow the instructions in your editor to edit\n"
> @@ -3588,25 +3617,24 @@ msgstr "Die Commit-Beschreibung #%d wird ausgelassen:"
>   
>   #: sequencer.c:1552
>   #, c-format
>   msgid "unknown command: %d"
>   msgstr "Unbekannter Befehl: %d"
>   
>   #: sequencer.c:1630
>   msgid "your index file is unmerged."
>   msgstr "Ihre Index-Datei ist nicht zusammengeführt."
>   
>   #: sequencer.c:1637
> -#, fuzzy
>   msgid "cannot fixup root commit"
> -msgstr "kann Commit %s (%s) nicht finden"
> +msgstr "kann fixup nicht auf Root-Commit anwenden"
>   
>   #: sequencer.c:1656
>   #, c-format
>   msgid "commit %s is a merge but no -m option was given."
>   msgstr "Commit %s ist ein Merge, aber die Option -m wurde nicht angegeben."
>   
>   #: sequencer.c:1664
>   #, c-format
>   msgid "commit %s does not have parent %d"
>   msgstr "Commit %s hat keinen Eltern-Commit %d"
>   
> @@ -3707,23 +3735,23 @@ msgstr "Kann Revert nicht während eines Cherry-Picks ausführen."
>   #, c-format
>   msgid "invalid key: %s"
>   msgstr "Ungültiger Schlüssel: %s"
>   
>   #: sequencer.c:2197
>   #, c-format
>   msgid "invalid value for %s: %s"
>   msgstr "Ungültiger Wert für %s: %s"
>   
>   #: sequencer.c:2268
>   msgid "unusable squash-onto"
> -msgstr ""
> +msgstr "Unbenutzbares squash-onto."
>   
>   #: sequencer.c:2284
>   #, c-format
>   msgid "malformed options sheet: '%s'"
>   msgstr "Fehlerhaftes Optionsblatt: '%s'"
>   
>   #: sequencer.c:2322
>   msgid "a cherry-pick or revert is already in progress"
>   msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang"
>   
>   #: sequencer.c:2323
> @@ -3824,69 +3852,65 @@ msgid ""
>   "\n"
>   msgstr ""
>   "Ausführung erfolgreich: %s\n"
>   "Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
>   "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
>   "Führen Sie dann aus:\n"
>   "\n"
>   "  git rebase --continue\n"
>   "\n"
>   
>   #: sequencer.c:2770
> -#, fuzzy
>   msgid "writing fake root commit"
> -msgstr "nichts zu committen\n"
> +msgstr "unechten Root-Commit schreiben"
>   
>   #: sequencer.c:2775
>   msgid "writing squash-onto"
> -msgstr ""
> +msgstr "squash-onto schreiben"
>   
>   #: sequencer.c:2810
> -#, fuzzy, c-format
> +#, c-format
>   msgid "failed to find tree of %s"
>   msgstr "Fehler beim Finden des \"Tree\"-Objektes von %s."
>   
>   #: sequencer.c:2828
> -#, fuzzy
>   msgid "could not write index"
> -msgstr "Konnte den Index nicht lesen."
> +msgstr "Konnte Index nicht schreiben."
>   
>   #: sequencer.c:2860
> -#, fuzzy
>   msgid "cannot merge without a current revision"
> -msgstr "Kann '%s' nicht ohne vorherigen Commit ausführen"
> +msgstr "Kann nicht ohne einen aktuellen Commit mergen."
>   
>   #: sequencer.c:2883
> -#, fuzzy, c-format
> +#, c-format
>   msgid "could not resolve '%s'"
> -msgstr "Konnte '%s' nicht löschen"
> +msgstr "Konnte '%s' nicht auflösen."
>   
>   #: sequencer.c:2905
> -#, fuzzy, c-format
> +#, c-format
>   msgid "could not get commit message of '%s'"
> -msgstr "Konnte Commit-Beschreibung von %s nicht lesen."
> +msgstr "Konnte keine Commit-Beschreibung von '%s' bekommen."
>   
>   #: sequencer.c:2915 sequencer.c:2940
> -#, fuzzy, c-format
> +#, c-format
>   msgid "could not write '%s'"
> -msgstr "Konnte nicht nach '%s' schreiben."
> +msgstr "Konnte '%s' nicht schreiben."
>   
>   #: sequencer.c:3004
> -#, fuzzy, c-format
> +#, c-format
>   msgid "could not even attempt to merge '%.*s'"
> -msgstr "konnte '%s' nicht öffnen oder lesen"
> +msgstr "Konnte nicht einmal versuchen '%.*s' zu mergen."
>   
>   #: sequencer.c:3020
> -#, fuzzy
>   msgid "merge: Unable to write new index file"
> -msgstr "%s: Konnte neue Index-Datei nicht schreiben"
> +msgstr "merge: Konnte neue Index-Datei nicht schreiben."
>   
>   #: sequencer.c:3087
>   #, c-format
>   msgid "Applied autostash.\n"
>   msgstr "Automatischen Stash angewendet.\n"
>   
>   #: sequencer.c:3099
>   #, c-format
>   msgid "cannot store %s"
>   msgstr "kann %s nicht speichern"
>   
> @@ -3905,22 +3929,30 @@ msgstr ""
>   #, c-format
>   msgid ""
>   "Could not execute the todo command\n"
>   "\n"
>   "    %.*s\n"
>   "It has been rescheduled; To edit the command before continuing, please\n"
>   "edit the todo list first:\n"
>   "\n"
>   "    git rebase --edit-todo\n"
>   "    git rebase --continue\n"
>   msgstr ""
> +"Konnte TODO-Befehl nicht ausführen\n"
> +"\n"
> +"    %.*s\n"
> +"Dieser wurde neu angesetzt; Um den Befehl zu bearbeiten, bevor fortgesetzt wird,\n"
> +"bearbeiten Sie bitte zuerst die TODO-Liste:\n"
> +"\n"
> +"    git rebase --edit-todo\n"
> +"    git rebase --continue\n"
>   
>   #: sequencer.c:3201
>   #, c-format
>   msgid "Stopped at %s...  %.*s\n"
>   msgstr "Angehalten bei %s... %.*s\n"
>   
>   #: sequencer.c:3263
>   #, c-format
>   msgid "unknown command %d"
>   msgstr "Unbekannter Befehl %d"
>   
> @@ -3961,25 +3993,25 @@ msgstr "Ungültige Inhalte: '%s'"
>   msgid ""
>   "\n"
>   "You have uncommitted changes in your working tree. Please, commit them\n"
>   "first and then run 'git rebase --continue' again."
>   msgstr ""
>   "\n"
>   "Sie haben nicht committete Änderungen in Ihrem Arbeitsverzeichnis. Bitte\n"
>   "committen Sie diese zuerst und führen Sie dann 'git rebase --continue'\n"
>   "erneut aus."
>   
>   #: sequencer.c:3454 sequencer.c:3492
> -#, fuzzy, c-format
> +#, c-format
>   msgid "could not write file: '%s'"
> -msgstr "konnte Datei '%s' nicht erstellen"
> +msgstr "Konnte Datei nicht schreiben: '%s'"
>   
>   #: sequencer.c:3507
>   msgid "could not remove CHERRY_PICK_HEAD"
>   msgstr "Konnte CHERRY_PICK_HEAD nicht löschen."
>   
>   #: sequencer.c:3514
>   msgid "could not commit staged changes."
>   msgstr "Konnte Änderungen aus der Staging-Area nicht committen."
>   
>   #: sequencer.c:3611
>   #, c-format
> @@ -4388,25 +4420,25 @@ msgstr "Fehler bei Rekursion in Submodul-Pfad '%s'"
>   
>   #: submodule.c:1863
>   msgid "could not start ls-files in .."
>   msgstr "Konnte 'ls-files' nicht in .. starten"
>   
>   #: submodule.c:1902
>   #, c-format
>   msgid "ls-tree returned unexpected return code %d"
>   msgstr "ls-tree mit unerwartetem Rückgabewert %d beendet"
>   
>   #: submodule-config.c:230
> -#, fuzzy, c-format
> +#, c-format
>   msgid "ignoring suspicious submodule name: %s"
> -msgstr "Ignoriere Referenz mit fehlerhaftem Namen %s"
> +msgstr "Ignoriere verdächtigen Submodulnamen: %s"
>   
>   #: submodule-config.c:294
>   msgid "negative values not allowed for submodule.fetchjobs"
>   msgstr "Negative Werte für submodule.fetchjobs nicht erlaubt."
>   
>   #: submodule-config.c:467
>   #, c-format
>   msgid "invalid value for %s"
>   msgstr "Ungültiger Wert für %s"
>   
>   #: trailer.c:238
> @@ -4466,25 +4498,24 @@ msgstr "konnte temporäre Datei nicht zu %s umbenennen"
>   #: transport.c:116
>   #, c-format
>   msgid "Would set upstream of '%s' to '%s' of '%s'\n"
>   msgstr "Würde Upstream-Branch von '%s' zu '%s' von '%s' setzen\n"
>   
>   #: transport.c:208
>   #, c-format
>   msgid "transport: invalid depth option '%s'"
>   msgstr "transport: ungültige --depth Option '%s'"
>   
>   #: transport.c:584
> -#, fuzzy
>   msgid "could not parse transport.color.* config"
> -msgstr "konnte Autor-Skript nicht parsen"
> +msgstr "Konnte transport.color.* Konfiguration nicht parsen."
>   
>   #: transport.c:996
>   #, c-format
>   msgid ""
>   "The following submodule paths contain changes that can\n"
>   "not be found on any remote:\n"
>   msgstr ""
>   "Die folgenden Submodul-Pfade enthalten Änderungen, die in keinem\n"
>   "Remote-Repository gefunden wurden:\n"
>   
>   #: transport.c:1000
> @@ -6090,51 +6121,50 @@ msgid "--bisect-clean-state requires no arguments"
>   msgstr "--bisect-clean-state erwartet keine Argumente."
>   
>   #: builtin/blame.c:29
>   msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
>   msgstr "git blame [<Optionen>] [<rev-opts>] [<Commit>] [--] <Datei>"
>   
>   #: builtin/blame.c:34
>   msgid "<rev-opts> are documented in git-rev-list(1)"
>   msgstr "<rev-opts> sind dokumentiert in git-rev-list(1)"
>   
>   #: builtin/blame.c:404
> -#, fuzzy, c-format
> +#, c-format
>   msgid "expecting a color: %s"
> -msgstr "Formatfarben beachten"
> +msgstr "Erwarte eine Farbe: %s"
>   
>   #: builtin/blame.c:411
>   msgid "must end with a color"
> -msgstr ""
> +msgstr "Muss mit einer Farbe enden."
>   
>   #: builtin/blame.c:697
> -#, fuzzy, c-format
> +#, c-format
>   msgid "invalid color '%s' in color.blame.repeatedLines"
> -msgstr "Ignoriere ungültige Farbe '%.*s' in log.graphColors"
> +msgstr "Ungültige Farbe '%s' in color.blame.repeatedLines."
>   
>   #: builtin/blame.c:715
> -#, fuzzy
>   msgid "invalid value for blame.coloring"
> -msgstr "Ungültiger Wert für --missing."
> +msgstr "Ungültiger Wert für blame.coloring."
>   
>   #: builtin/blame.c:786
>   msgid "Show blame entries as we find them, incrementally"
>   msgstr "\"blame\"-Einträge schrittweise anzeigen, während wir sie generieren"
>   
>   #: builtin/blame.c:787
>   msgid "Show blank SHA-1 for boundary commits (Default: off)"
>   msgstr "leere SHA-1 für Grenz-Commits anzeigen (Standard: aus)"
>   
>   #: builtin/blame.c:788
>   msgid "Do not treat root commits as boundaries (Default: off)"
> -msgstr "Ursprungs-Commits nicht als Grenzen behandeln (Standard: aus)"
> +msgstr "Root-Commits nicht als Grenzen behandeln (Standard: aus)"
>   
>   #: builtin/blame.c:789
>   msgid "Show work cost statistics"
>   msgstr "Statistiken zum Arbeitsaufwand anzeigen"
>   
>   #: builtin/blame.c:790
>   msgid "Force progress reporting"
>   msgstr "Fortschrittsanzeige erzwingen"
>   
>   #: builtin/blame.c:791
>   msgid "Show output score for blame entries"
> @@ -6177,27 +6207,27 @@ msgstr "Den Namen des Autors und den Zeitstempel unterdrücken (Standard: aus)"
>   #: builtin/blame.c:800
>   msgid "Show author email instead of name (Default: off)"
>   msgstr ""
>   "Anstatt des Namens die E-Mail-Adresse des Autors anzeigen (Standard: aus)"
>   
>   #: builtin/blame.c:801
>   msgid "Ignore whitespace differences"
>   msgstr "Unterschiede im Whitespace ignorieren"
>   
>   #: builtin/blame.c:802
>   msgid "color redundant metadata from previous line differently"
> -msgstr ""
> +msgstr "redundante Metadaten der vorherigen Zeile unterschiedlich einfärben"
>   
>   #: builtin/blame.c:803
>   msgid "color lines by age"
> -msgstr ""
> +msgstr "Zeilen nach Alter einfärben"
>   
>   #: builtin/blame.c:810
>   msgid "Use an experimental heuristic to improve diffs"
>   msgstr ""
>   "eine experimentelle Heuristik zur Verbesserung der Darstellung\n"
>   "von Unterschieden verwenden"
>   
>   #: builtin/blame.c:812
>   msgid "Spend extra cycles to find better match"
>   msgstr "Länger arbeiten, um bessere Übereinstimmungen zu finden"
>   
> @@ -8147,29 +8177,28 @@ msgid ""
>   "ignore changes to submodules, optional when: all, dirty, untracked. "
>   "(Default: all)"
>   msgstr ""
>   "Änderungen in Submodulen ignorieren, optional wenn: all, dirty, untracked. "
>   "(Standard: all)"
>   
>   #: builtin/commit.c:1329
>   msgid "list untracked files in columns"
>   msgstr "unversionierte Dateien in Spalten auflisten"
>   
>   #: builtin/commit.c:1330
> -#, fuzzy
>   msgid "do not detect renames"
> -msgstr "keine Abfrage von Remote-Repositories"
> +msgstr "keine Umbenennungen ermitteln"
>   
>   #: builtin/commit.c:1332
>   msgid "detect renames, optionally set similarity index"
> -msgstr ""
> +msgstr "Umbenennungen erkennen, optional Index für Gleichheit setzen"
>   
>   #: builtin/commit.c:1352
>   msgid "Unsupported combination of ignored and untracked-files arguments"
>   msgstr ""
>   "Nicht unterstützte Kombination von ignored und untracked-files Argumenten."
>   
>   #: builtin/commit.c:1450
>   msgid "suppress summary after successful commit"
>   msgstr "Zusammenfassung nach erfolgreichem Commit unterdrücken"
>   
>   #: builtin/commit.c:1451
> @@ -8346,68 +8375,68 @@ msgid ""
>   "Repository has been updated, but unable to write\n"
>   "new_index file. Check that disk is not full and quota is\n"
>   "not exceeded, and then \"git reset HEAD\" to recover."
>   msgstr ""
>   "Das Repository wurde aktualisiert, aber die \"new_index\"-Datei\n"
>   "konnte nicht geschrieben werden. Prüfen Sie, dass Ihre Festplatte nicht\n"
>   "voll und Ihr Kontingent nicht aufgebraucht ist und führen Sie\n"
>   "anschließend \"git reset HEAD\" zu Wiederherstellung aus."
>   
>   #: builtin/commit-graph.c:9
>   msgid "git commit-graph [--object-dir <objdir>]"
> -msgstr ""
> +msgstr "git commit-graph [--object-dir <Objektverzeichnis>]"
>   
>   #: builtin/commit-graph.c:10 builtin/commit-graph.c:16
>   msgid "git commit-graph read [--object-dir <objdir>]"
> -msgstr ""
> +msgstr "git commit-graph read [--object-dir <Objektverzeichnis>]"
>   
>   #: builtin/commit-graph.c:11 builtin/commit-graph.c:21
>   msgid ""
>   "git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--"
>   "stdin-commits]"
> -msgstr ""
> +msgstr "git commit-graph write [--object-dir <Objektverzeichnis>] [--append] [--stdin-packs|--stdin-commits]"
>   
>   #: builtin/commit-graph.c:39 builtin/commit-graph.c:92
>   #: builtin/commit-graph.c:147 builtin/fetch.c:161 builtin/log.c:1466
>   msgid "dir"
>   msgstr "Verzeichnis"
>   
>   #: builtin/commit-graph.c:40 builtin/commit-graph.c:93
>   #: builtin/commit-graph.c:148
>   msgid "The object directory to store the graph"
> -msgstr ""
> +msgstr "Das Objektverzeichnis zum Speichern des Graphen."
>   
>   #: builtin/commit-graph.c:95
>   msgid "scan pack-indexes listed by stdin for commits"
> -msgstr ""
> +msgstr "durch Standard-Eingabe gelistete Pack-Indexe nach Commits scannen"
>   
>   #: builtin/commit-graph.c:97
>   msgid "start walk at commits listed by stdin"
> -msgstr ""
> +msgstr "Lauf bei Commits beginnen, die über die Standard-Eingabe gelistet sind"
>   
>   #: builtin/commit-graph.c:99
>   msgid "include all commits already in the commit-graph file"
> -msgstr ""
> +msgstr "alle Commits einschließen, die sich bereits in der Commit-Graph-Datei befinden"
>   
>   #: builtin/commit-graph.c:108
>   msgid "cannot use both --stdin-commits and --stdin-packs"
> -msgstr ""
> +msgstr "Kann nicht --stdin-commits und --stdin-packs benutzen."
>   
>   #: builtin/config.c:10
>   msgid "git config [<options>]"
>   msgstr "git config [<Optionen>]"
>   
>   #: builtin/config.c:101
> -#, fuzzy, c-format
> +#, c-format
>   msgid "unrecognized --type argument, %s"
> -msgstr "nicht erkanntes Argument: %s"
> +msgstr "nicht erkanntes --type Argument, %s"
>   
>   #: builtin/config.c:123
>   msgid "Config file location"
>   msgstr "Ort der Konfigurationsdatei"
>   
>   #: builtin/config.c:124
>   msgid "use global config file"
>   msgstr "globale Konfigurationsdatei verwenden"
>   
>   #: builtin/config.c:125
>   msgid "use system config file"
> @@ -8486,25 +8515,24 @@ msgid "find the color configured: slot [default]"
>   msgstr "die konfigurierte Farbe finden: Slot [Standard]"
>   
>   #: builtin/config.c:143
>   msgid "find the color setting: slot [stdout-is-tty]"
>   msgstr "die Farbeinstellung finden: Slot [Standard-Ausgabe-ist-Terminal]"
>   
>   #: builtin/config.c:144
>   msgid "Type"
>   msgstr "Typ"
>   
>   #: builtin/config.c:145
> -#, fuzzy
>   msgid "value is given this type"
> -msgstr "Wert ist ein Verfallsdatum"
> +msgstr "Wert ist mit diesem Typ angegeben"
>   
>   #: builtin/config.c:146
>   msgid "value is \"true\" or \"false\""
>   msgstr "Wert ist \"true\" oder \"false\""
>   
>   #: builtin/config.c:147
>   msgid "value is decimal number"
>   msgstr "Wert ist eine Dezimalzahl"
>   
>   #: builtin/config.c:148
>   msgid "value is --bool or --int"
> @@ -8533,34 +8561,33 @@ msgstr "nur Variablennamen anzeigen"
>   #: builtin/config.c:154
>   msgid "respect include directives on lookup"
>   msgstr "beachtet \"include\"-Direktiven beim Nachschlagen"
>   
>   #: builtin/config.c:155
>   msgid "show origin of config (file, standard input, blob, command line)"
>   msgstr ""
>   "Ursprung der Konfiguration anzeigen (Datei, Standard-Eingabe, Blob, "
>   "Befehlszeile)"
>   
>   #: builtin/config.c:156
> -#, fuzzy
>   msgid "value"
> -msgstr "Schlüssel=Wert"
> +msgstr "Wert"
>   
>   #: builtin/config.c:156
>   msgid "with --get, use default value when missing entry"
> -msgstr ""
> +msgstr "mit --get, benutze den Standardwert, wenn der Eintrag fehlt"
>   
>   #: builtin/config.c:332
> -#, fuzzy, c-format
> +#, c-format
>   msgid "failed to format default config value: %s"
> -msgstr "Konnte Datei '%s' nicht erstellen"
> +msgstr "Fehler beim Formatieren des Standardkonfigurationswertes: %s"
>   
>   #: builtin/config.c:431
>   msgid "unable to parse default color value"
>   msgstr "konnte Standard-Farbwert nicht parsen"
>   
>   #: builtin/config.c:575
>   #, c-format
>   msgid ""
>   "# This is Git's per-user configuration file.\n"
>   "[user]\n"
>   "# Please adapt and uncomment the following lines:\n"
> @@ -8570,25 +8597,24 @@ msgstr ""
>   "# Das ist Git's benutzerspezifische Konfigurationsdatei.\n"
>   "[user]\n"
>   "# Bitte passen Sie die folgenden Zeilen an und kommentieren Sie diese aus:\n"
>   "#\tname = %s\n"
>   "#\temail = %s\n"
>   
>   #: builtin/config.c:603
>   msgid "--local can only be used inside a git repository"
>   msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
>   
>   #: builtin/config.c:606
> -#, fuzzy
>   msgid "--blob can only be used inside a git repository"
> -msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
> +msgstr "--blob kann nur innerhalb eines Git-Repositories verwendet werden."
>   
>   #: builtin/config.c:735
>   #, c-format
>   msgid "cannot create configuration file %s"
>   msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
>   
>   #: builtin/config.c:748
>   #, c-format
>   msgid ""
>   "cannot overwrite multiple values with a single value\n"
>   "       Use a regexp, --add or --replace-all to change %s."
> @@ -9147,24 +9173,24 @@ msgid "non-fast-forward"
>   msgstr "kein Vorspulen"
>   
>   #: builtin/fetch.c:795
>   #, c-format
>   msgid "%s did not send all necessary objects\n"
>   msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
>   
>   #: builtin/fetch.c:815
>   #, c-format
>   msgid "reject %s because shallow roots are not allowed to be updated"
>   msgstr ""
> -"%s wurde zurückgewiesen, da Ursprungs-Commits von Repositories mit "
> -"unvollständiger Historie (shallow) nicht aktualisiert werden dürfen."
> +"%s wurde zurückgewiesen, da Root-Commits von Repositories mit unvollständiger\n"
> +"Historie (shallow) nicht aktualisiert werden dürfen."
>   
>   #: builtin/fetch.c:903 builtin/fetch.c:999
>   #, c-format
>   msgid "From %.*s\n"
>   msgstr "Von %.*s\n"
>   
>   #: builtin/fetch.c:914
>   #, c-format
>   msgid ""
>   "some local refs could not be updated; try running\n"
>   " 'git remote prune %s' to remove any old, conflicting branches"
> @@ -9464,33 +9490,33 @@ msgstr "mehr Gründlichkeit (erhöht Laufzeit)"
>   msgid "enable auto-gc mode"
>   msgstr "\"auto-gc\" Modus aktivieren"
>   
>   #: builtin/gc.c:508
>   msgid "force running gc even if there may be another gc running"
>   msgstr ""
>   "Ausführung von \"git gc\" erzwingen, selbst wenn ein anderes\n"
>   "\"git gc\" bereits ausgeführt wird"
>   
>   #: builtin/gc.c:511
>   msgid "repack all other packs except the largest pack"
> -msgstr ""
> +msgstr "alle anderen Pakete, außer das größte Paket, neu packen"
>   
>   #: builtin/gc.c:528
> -#, fuzzy, c-format
> +#, c-format
>   msgid "failed to parse gc.logexpiry value %s"
> -msgstr "Fehler beim Parsen des Wertes '%s' von gc.logexpiry"
> +msgstr "Fehler beim Parsen des Wertes '%s' von gc.logexpiry."
>   
>   #: builtin/gc.c:539
> -#, fuzzy, c-format
> +#, c-format
>   msgid "failed to parse prune expiry value %s"
> -msgstr "Fehler beim Parsen des Wertes '%s' von gc.logexpiry"
> +msgstr "Fehler beim Parsen des \"prune expiry\" Wertes %s"
>   
>   #: builtin/gc.c:559
>   #, c-format
>   msgid "Auto packing the repository in background for optimum performance.\n"
>   msgstr ""
>   "Die Datenbank des Repositories wird für eine optimale Performance im\n"
>   "Hintergrund komprimiert.\n"
>   
>   #: builtin/gc.c:561
>   #, c-format
>   msgid "Auto packing the repository for optimum performance.\n"
> @@ -10080,25 +10106,24 @@ msgstr "Kann existierende Informationen zu Objekt %s nicht lesen."
>   #: builtin/index-pack.c:825
>   #, c-format
>   msgid "cannot read existing object %s"
>   msgstr "Kann existierendes Objekt %s nicht lesen."
>   
>   #: builtin/index-pack.c:839
>   #, c-format
>   msgid "invalid blob object %s"
>   msgstr "ungültiges Blob-Objekt %s"
>   
>   #: builtin/index-pack.c:842 builtin/index-pack.c:860
> -#, fuzzy
>   msgid "fsck error in packed object"
> -msgstr "gepackte Objekte ignorieren"
> +msgstr "fsck Fehler in gepacktem Objekt"
>   
>   #: builtin/index-pack.c:857
>   #, c-format
>   msgid "invalid %s"
>   msgstr "Ungültiger Objekt-Typ %s"
>   
>   #: builtin/index-pack.c:862
>   #, c-format
>   msgid "Not all child objects of %s are reachable"
>   msgstr "Nicht alle Kind-Objekte von %s sind erreichbar"
>   
> @@ -10243,25 +10268,24 @@ msgid "--fix-thin cannot be used without --stdin"
>   msgstr "Die Option --fix-thin kann nicht ohne --stdin verwendet werden."
>   
>   #: builtin/index-pack.c:1776
>   msgid "--stdin requires a git repository"
>   msgstr "--stdin erfordert ein Git-Repository"
>   
>   #: builtin/index-pack.c:1782
>   msgid "--verify with no packfile name given"
>   msgstr "Die Option --verify wurde ohne Namen der Paketdatei angegeben."
>   
>   #: builtin/index-pack.c:1832 builtin/unpack-objects.c:578
> -#, fuzzy
>   msgid "fsck error in pack objects"
> -msgstr "Fehler in Objekt: %s"
> +msgstr "fsck Fehler beim Packen von Objekten"
>   
>   #: builtin/init-db.c:55
>   #, c-format
>   msgid "cannot stat '%s'"
>   msgstr "Kann '%s' nicht lesen"
>   
>   #: builtin/init-db.c:61
>   #, c-format
>   msgid "cannot stat template '%s'"
>   msgstr "kann Vorlage '%s' nicht lesen"
>   
> @@ -12098,30 +12122,30 @@ msgstr "Schreibe Objekte"
>   msgid "disabling bitmap writing, as some objects are not being packed"
>   msgstr ""
>   "Deaktiviere Schreiben der Bitmap, da einige Objekte nicht in eine Pack-"
>   "Datei\n"
>   "geschrieben wurden."
>   
>   #: builtin/pack-objects.c:1765
>   msgid "Counting objects"
>   msgstr "Zähle Objekte"
>   
>   #: builtin/pack-objects.c:1895
> -#, fuzzy, c-format
> +#, c-format
>   msgid "unable to get size of %s"
> -msgstr "Konnte %s nicht nach %s verschieben"
> +msgstr "Konnte Größe von %s nicht bestimmen."
>   
>   #: builtin/pack-objects.c:1910
> -#, fuzzy, c-format
> +#, c-format
>   msgid "unable to parse object header of %s"
> -msgstr "Konnte Objekt '%s' nicht parsen."
> +msgstr "Konnte Kopfbereich von Objekt '%s' nicht parsen."
>   
>   #: builtin/pack-objects.c:2564
>   msgid "Compressing objects"
>   msgstr "Komprimiere Objekte"
>   
>   #: builtin/pack-objects.c:2735
>   msgid "invalid value for --missing"
>   msgstr "Ungültiger Wert für --missing."
>   
>   #: builtin/pack-objects.c:3067
>   #, c-format
> @@ -12253,25 +12277,24 @@ msgstr "dünnere Pakete erzeugen"
>   
>   #: builtin/pack-objects.c:3163
>   msgid "create packs suitable for shallow fetches"
>   msgstr ""
>   "Pakete geeignet für Abholung mit unvollständiger Historie (shallow) erzeugen"
>   
>   #: builtin/pack-objects.c:3165
>   msgid "ignore packs that have companion .keep file"
>   msgstr "Pakete ignorieren, die .keep Dateien haben"
>   
>   #: builtin/pack-objects.c:3167
> -#, fuzzy
>   msgid "ignore this pack"
> -msgstr "kleinere Pakete verwenden"
> +msgstr "dieses Paket ignorieren"
>   
>   #: builtin/pack-objects.c:3169
>   msgid "pack compression level"
>   msgstr "Komprimierungsgrad für Paketierung"
>   
>   #: builtin/pack-objects.c:3171
>   msgid "do not hide commits by grafts"
>   msgstr "keine künstlichen Vorgänger-Commits (\"grafts\") verbergen"
>   
>   #: builtin/pack-objects.c:3173
>   msgid "use a bitmap index if available to speed up counting objects"
> @@ -12287,33 +12310,32 @@ msgid "handling for missing objects"
>   msgstr "Behandlung für fehlende Objekte"
>   
>   #: builtin/pack-objects.c:3181
>   msgid "do not pack objects in promisor packfiles"
>   msgstr ""
>   "keine Objekte aus Packdateien von partiell geklonten Remote-Repositories "
>   "packen"
>   
>   #: builtin/pack-objects.c:3205
>   #, c-format
>   msgid "delta chain depth %d is too deep, forcing %d"
> -msgstr ""
> +msgstr "Tiefe für Verkettung von Unterschieden %d ist zu tief, erzwinge %d"
>   
>   #: builtin/pack-objects.c:3210
>   #, c-format
>   msgid "pack.deltaCacheLimit is too high, forcing %d"
> -msgstr ""
> +msgstr "pack.deltaCacheLimit ist zu hoch, erzwinge %d"
>   
>   #: builtin/pack-objects.c:3338
> -#, fuzzy
>   msgid "Enumerating objects"
> -msgstr "Schreibe Objekte"
> +msgstr "Objekte aufzählen"
>   
>   #: builtin/pack-refs.c:7
>   msgid "git pack-refs [<options>]"
>   msgstr "git pack-refs [<Optionen>]"
>   
>   #: builtin/pack-refs.c:15
>   msgid "pack everything"
>   msgstr "alles packen"
>   
>   #: builtin/pack-refs.c:16
>   msgid "prune loose refs (default)"
> @@ -12920,29 +12942,28 @@ msgid "git rebase--helper [<options>]"
>   msgstr "git rebase--helper [<Optionen>]"
>   
>   #: builtin/rebase--helper.c:24
>   msgid "keep empty commits"
>   msgstr "leere Commits behalten"
>   
>   #: builtin/rebase--helper.c:26 builtin/revert.c:123
>   msgid "allow commits with empty messages"
>   msgstr "Commits mit leerer Beschreibung erlauben"
>   
>   #: builtin/rebase--helper.c:27
> -#, fuzzy
>   msgid "rebase merge commits"
> -msgstr "ungültiger Merge-Tag in Commit '%s'"
> +msgstr "Rebase auf Merge-Commits ausführen"
>   
>   #: builtin/rebase--helper.c:29
>   msgid "keep original branch points of cousins"
> -msgstr ""
> +msgstr "originale Branch-Punkte der Cousins behalten"
>   
>   #: builtin/rebase--helper.c:30
>   msgid "continue rebase"
>   msgstr "Rebase fortsetzen"
>   
>   #: builtin/rebase--helper.c:32
>   msgid "abort rebase"
>   msgstr "Rebase abbrechen"
>   
>   #: builtin/rebase--helper.c:35
>   msgid "make rebase script"
> @@ -12966,23 +12987,23 @@ msgstr "nicht erforderliche \"pick\"-Befehle auslassen"
>   
>   #: builtin/rebase--helper.c:45
>   msgid "rearrange fixup/squash lines"
>   msgstr "fixup/squash-Zeilen umordnen"
>   
>   #: builtin/rebase--helper.c:47
>   msgid "insert exec commands in todo list"
>   msgstr "\"exec\"-Befehle in TODO-Liste einfügen"
>   
>   #: builtin/rebase--helper.c:68
>   msgid "--[no-]rebase-cousins has no effect without --rebase-merges"
> -msgstr ""
> +msgstr "--[no-]rebase-cousins hat ohne --rebase-merges keine Auswirkung"
>   
>   #: builtin/receive-pack.c:31
>   msgid "git receive-pack <git-dir>"
>   msgstr "git receive-pack <Git-Verzeichnis>"
>   
>   #: builtin/receive-pack.c:842
>   msgid ""
>   "By default, updating the current branch in a non-bare repository\n"
>   "is denied, because it will make the index and work tree inconsistent\n"
>   "with what you pushed, and will require 'git reset --hard' to match\n"
>   "the work tree to HEAD.\n"
> @@ -13288,25 +13309,25 @@ msgstr " ???"
>   #: builtin/remote.c:962
>   #, c-format
>   msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
>   msgstr "ungültiges branch.%s.merge; kann Rebase nicht auf > 1 Branch ausführen"
>   
>   #: builtin/remote.c:971
>   #, c-format
>   msgid "rebases interactively onto remote %s"
>   msgstr "interaktiver Rebase auf Remote-Branch %s"
>   
>   #: builtin/remote.c:973
> -#, fuzzy, c-format
> +#, c-format
>   msgid "rebases interactively (with merges) onto remote %s"
> -msgstr "interaktiver Rebase auf Remote-Branch %s"
> +msgstr "interaktiver Rebase (mit Merges) auf Remote-Branch %s"
>   
>   #: builtin/remote.c:976
>   #, c-format
>   msgid "rebases onto remote %s"
>   msgstr "Rebase auf Remote-Branch %s"
>   
>   #: builtin/remote.c:980
>   #, c-format
>   msgid " merges with remote %s"
>   msgstr " führt mit Remote-Branch %s zusammen"
>   
> @@ -13650,27 +13671,24 @@ msgstr "maximale Anzahl von Threads limitieren"
>   
>   #: builtin/repack.c:210
>   msgid "maximum size of each packfile"
>   msgstr "maximale Größe für jede Paketdatei"
>   
>   #: builtin/repack.c:212
>   msgid "repack objects in packs marked with .keep"
>   msgstr ""
>   "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
>   
>   #: builtin/repack.c:214
> -#, fuzzy
>   msgid "do not repack this pack"
> -msgstr ""
> -"keine Objekte aus Packdateien von partiell geklonten Remote-Repositories "
> -"packen"
> +msgstr "dieses Paket nicht neu packen"
>   
>   #: builtin/repack.c:224
>   msgid "cannot delete packs in a precious-objects repo"
>   msgstr "kann Pack-Dateien in precious-objects Repository nicht löschen"
>   
>   #: builtin/repack.c:228
>   msgid "--keep-unreachable and -A are incompatible"
>   msgstr "--keep-unreachable und -A sind inkompatibel"
>   
>   #: builtin/repack.c:425 builtin/worktree.c:139
>   #, c-format
> @@ -13682,25 +13700,24 @@ msgid "git replace [-f] <object> <replacement>"
>   msgstr "git replace [-f] <Objekt> <Ersetzung>"
>   
>   #: builtin/replace.c:23
>   msgid "git replace [-f] --edit <object>"
>   msgstr "git replace [-f] --edit <Objekt>"
>   
>   #: builtin/replace.c:24
>   msgid "git replace [-f] --graft <commit> [<parent>...]"
>   msgstr "git replace [-f] --graft <Commit> [<Eltern-Commit>...]"
>   
>   #: builtin/replace.c:25
> -#, fuzzy
>   msgid "git replace [-f] --convert-graft-file"
> -msgstr "git replace [-f] --edit <Objekt>"
> +msgstr "git replace [-f] --convert-graft-file"
>   
>   #: builtin/replace.c:26
>   msgid "git replace -d <object>..."
>   msgstr "git replace -d <Objekt>..."
>   
>   #: builtin/replace.c:27
>   msgid "git replace [--format=<format>] [-l [<pattern>]]"
>   msgstr "git replace [--format=<Format>] [-l [<Muster>]]"
>   
>   #: builtin/replace.c:371 builtin/replace.c:415 builtin/replace.c:445
>   #, c-format
> @@ -13733,48 +13750,49 @@ msgstr "Der ursprüngliche Commit '%s' hat eine GPG-Signatur."
>   
>   #: builtin/replace.c:461
>   msgid "the signature will be removed in the replacement commit!"
>   msgstr "Die Signatur wird in dem Ersetzungs-Commit entfernt!"
>   
>   #: builtin/replace.c:471
>   #, c-format
>   msgid "could not write replacement commit for: '%s'"
>   msgstr "Konnte Ersetzungs-Commit für '%s' nicht schreiben"
>   
>   #: builtin/replace.c:514
> -#, fuzzy, c-format
> +#, c-format
>   msgid ""
>   "could not convert the following graft(s):\n"
>   "%s"
> -msgstr "Würde das folgende Element entfernen:"
> +msgstr ""
> +"Konnte die folgenden künstlichen Vorgänger (\"grafts\") nicht konvertieren:\n"
> +"%s"
>   
>   #: builtin/replace.c:535
>   msgid "list replace refs"
>   msgstr "ersetzende Referenzen auflisten"
>   
>   #: builtin/replace.c:536
>   msgid "delete replace refs"
>   msgstr "ersetzende Referenzen löschen"
>   
>   #: builtin/replace.c:537
>   msgid "edit existing object"
>   msgstr "existierendes Objekt bearbeiten"
>   
>   #: builtin/replace.c:538
>   msgid "change a commit's parents"
>   msgstr "Eltern-Commits eines Commits ändern"
>   
>   #: builtin/replace.c:539
> -#, fuzzy
>   msgid "convert existing graft file"
> -msgstr "das Überschreiben bereits existierender Dateien erzwingen"
> +msgstr "existierende Datei des künstlichen Vorgängers (\"graft\") konvertieren"
>   
>   #: builtin/replace.c:540
>   msgid "replace the ref if it exists"
>   msgstr "die Referenz ersetzen, wenn sie existiert"
>   
>   #: builtin/replace.c:542
>   msgid "do not pretty-print contents for --edit"
>   msgstr "keine ansprechende Anzeige des Objektinhaltes für --edit"
>   
>   #: builtin/replace.c:543
>   msgid "use this format"
> @@ -14157,44 +14175,40 @@ msgid "use stateless RPC protocol"
>   msgstr "zustandsloses RPC-Protokoll verwenden"
>   
>   #: builtin/send-pack.c:178
>   msgid "read refs from stdin"
>   msgstr "Referenzen von der Standard-Eingabe lesen"
>   
>   #: builtin/send-pack.c:179
>   msgid "print status from remote helper"
>   msgstr "Status des Remote-Helpers ausgeben"
>   
>   #: builtin/serve.c:7
> -#, fuzzy
>   msgid "git serve [<options>]"
> -msgstr "git repack [<Optionen>]"
> +msgstr "git serve [<Optionen>]"
>   
>   #: builtin/serve.c:17 builtin/upload-pack.c:23
>   msgid "quit after a single request/response exchange"
>   msgstr "nach einem einzigen Request/Response-Austausch beenden"
>   
>   #: builtin/serve.c:19
> -#, fuzzy
>   msgid "exit immediately after advertising capabilities"
> -msgstr "direkt nach der initialen Angabe der Commits beenden"
> +msgstr "direkt nach Anzeige der angebotenen Fähigkeiten beenden"
>   
>   #: builtin/shortlog.c:14
> -#, fuzzy
>   msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
> -msgstr "git shortlog [<Optionen>] [<Commitbereich>] [[--] [<Pfad>...]]"
> +msgstr "git shortlog [<Optionen>] [<Commitbereich>] [[--] <Pfad>...]"
>   
>   #: builtin/shortlog.c:15
> -#, fuzzy
>   msgid "git log --pretty=short | git shortlog [<options>]"
> -msgstr "git worktree list [<Optionen>]"
> +msgstr "git log --pretty=short | git shortlog [<Optionen>]"
>   
>   #: builtin/shortlog.c:264
>   msgid "Group by committer rather than author"
>   msgstr "über Commit-Ersteller anstatt Autor gruppieren"
>   
>   #: builtin/shortlog.c:266
>   msgid "sort output according to the number of commits per author"
>   msgstr "die Ausgabe entsprechend der Anzahl von Commits pro Autor sortieren"
>   
>   #: builtin/shortlog.c:268
>   msgid "Suppress commit descriptions, only provides commit count"
> @@ -14205,27 +14219,24 @@ msgid "Show the email address of each author"
>   msgstr "die E-Mail-Adresse von jedem Autor anzeigen"
>   
>   #: builtin/shortlog.c:271
>   msgid "w[,i1[,i2]]"
>   msgstr "w[,i1[,i2]]"
>   
>   #: builtin/shortlog.c:272
>   msgid "Linewrap output"
>   msgstr "Ausgabe mit Zeilenumbrüchen"
>   
>   #: builtin/shortlog.c:298
> -#, fuzzy
>   msgid "too many arguments given outside repository"
> -msgstr ""
> -"zu viele Argumente angegeben, um Konfiguration zu Upstream-Branch zu "
> -"entfernen"
> +msgstr "zu viele Argumente außerhalb des Repositories angegeben"
>   
>   #: builtin/show-branch.c:12
>   msgid ""
>   "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
>   "\t\t[--current] [--color[=<when>] | --no-color] [--sparse]\n"
>   "\t\t[--more=<n> | --list | --independent | --merge-base]\n"
>   "\t\t[--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"
>   msgstr ""
>   "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
>   "\t\t[--current] [--color[=<Wann>] | --no-color] [--sparse]\n"
>   "\t\t[--more=<n> | --list | --independent | --merge-base]\n"
> @@ -15457,40 +15468,40 @@ msgstr "Arbeitsverzeichnisse älter als <Zeit> verfallen lassen"
>   #: builtin/worktree.c:229
>   #, c-format
>   msgid "'%s' already exists"
>   msgstr "'%s' existiert bereits"
>   
>   #: builtin/worktree.c:260
>   #, c-format
>   msgid "could not create directory of '%s'"
>   msgstr "Konnte Verzeichnis '%s' nicht erstellen."
>   
>   #: builtin/worktree.c:373 builtin/worktree.c:379
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Preparing worktree (new branch '%s')"
> -msgstr "Fehler beim Entfernen des Branches '%s'"
> +msgstr "Bereite Arbeitsverzeichnis vor (neuer Branch '%s')"
>   
>   #: builtin/worktree.c:375
>   #, c-format
>   msgid "Preparing worktree (resetting branch '%s'; was at %s)"
> -msgstr ""
> +msgstr "Bereite Arbeitsverzeichnis vor (setze Branch '%s' um; war bei %s)"
>   
>   #: builtin/worktree.c:384
>   #, c-format
>   msgid "Preparing worktree (checking out '%s')"
> -msgstr ""
> +msgstr "Bereite Arbeitsverzeichnis vor (checke '%s' aus)"
>   
>   #: builtin/worktree.c:390
> -#, fuzzy, c-format
> +#, c-format
>   msgid "Preparing worktree (detached HEAD %s)"
> -msgstr "Bereite %s vor (Identifikation %s)"
> +msgstr "Bereite Arbeitsverzeichnis vor (losgelöster HEAD %s)"
>   
>   #: builtin/worktree.c:431
>   msgid "checkout <branch> even if already checked out in other worktree"
>   msgstr ""
>   "<Branch> auschecken, auch wenn dieser bereits in einem anderen "
>   "Arbeitsverzeichnis ausgecheckt ist"
>   
>   #: builtin/worktree.c:434
>   msgid "create a new branch"
>   msgstr "neuen Branch erstellen"
>   
> @@ -15661,34 +15672,33 @@ msgstr ""
>   "Ziehen Sie in Betracht\n"
>   "\n"
>   "\tchmod 0700 %s\n"
>   "\n"
>   "auszuführen."
>   
>   #: credential-cache--daemon.c:271
>   msgid "print debugging messages to stderr"
>   msgstr "Meldungen zur Fehlersuche in Standard-Fehlerausgabe ausgeben"
>   
>   #: git.c:26
> -#, fuzzy
>   msgid ""
>   "git [--version] [--help] [-C <path>] [-c <name>=<value>]\n"
>   "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
>   "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
>   "bare]\n"
>   "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
>   "           <command> [<args>]"
>   msgstr ""
>   "git [--version] [--help] [-C <Pfad>] [-c <Name>=<Wert>]\n"
>   "           [--exec-path[=<Pfad>]] [--html-path] [--man-path] [--info-path]\n"
> -"           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
> +"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
>   "           [--git-dir=<Pfad>] [--work-tree=<Pfad>] [--namespace=<Name>]\n"
>   "           <Befehl> [<Argumente>]"
>   
>   #: git.c:33
>   msgid ""
>   "'git help -a' and 'git help -g' list available subcommands and some\n"
>   "concept guides. See 'git help <command>' or 'git help <concept>'\n"
>   "to read about a specific subcommand or concept."
>   msgstr ""
>   "'git help -a' und 'git help -g' listet verfügbare Unterbefehle und\n"
>   "einige Anleitungen zu Git-Konzepten auf. Benutzen Sie 'git help <Befehl>'\n"
> @@ -16223,23 +16233,23 @@ msgstr ""
>   "Es sieht so aus, als ob es das Verzeichnis $state_dir_base bereits gibt\n"
>   "und es könnte ein anderer Rebase im Gange sein. Wenn das der Fall ist,\n"
>   "probieren Sie bitte\n"
>   "\t$cmd_live_rebase\n"
>   "Wenn das nicht der Fall ist, probieren Sie bitte\n"
>   "\t$cmd_clear_stale_rebase\n"
>   "und führen Sie diesen Befehl nochmal aus. Es wird angehalten, falls noch\n"
>   "etwas Schützenswertes vorhanden ist."
>   
>   #: git-rebase.sh:509
>   msgid "error: cannot combine '--signoff' with '--preserve-merges'"
> -msgstr ""
> +msgstr "Fehler: '--signoff' und '--preserve-merges' können nicht kombiniert werden."
>   
>   #: git-rebase.sh:537
>   #, sh-format
>   msgid "invalid upstream '$upstream_name'"
>   msgstr "Ungültiger Upstream-Branch '$upstream_name'."
>   
>   #: git-rebase.sh:561
>   #, sh-format
>   msgid "$onto_name: there are more than one merge bases"
>   msgstr "$onto_name: es gibt mehr als eine Merge-Basis"
>   
> @@ -16664,51 +16674,57 @@ msgstr ""
>   #: git-parse-remote.sh:89
>   #, sh-format
>   msgid "See git-${cmd}(1) for details."
>   msgstr "Siehe git-${cmd}(1) für weitere Details."
>   
>   #: git-rebase--interactive.sh:142
>   #, sh-format
>   msgid "Rebasing ($new_count/$total)"
>   msgstr "Führe Rebase aus ($new_count/$total)"
>   
>   #: git-rebase--interactive.sh:158
> -#, fuzzy
>   msgid ""
>   "\n"
>   "Commands:\n"
>   "p, pick <commit> = use commit\n"
>   "r, reword <commit> = use commit, but edit the commit message\n"
>   "e, edit <commit> = use commit, but stop for amending\n"
>   "s, squash <commit> = use commit, but meld into previous commit\n"
>   "f, fixup <commit> = like \"squash\", but discard this commit's log message\n"
>   "x, exec <commit> = run command (the rest of the line) using shell\n"
>   "d, drop <commit> = remove commit\n"
>   "l, label <label> = label current HEAD with a name\n"
>   "t, reset <label> = reset HEAD to a label\n"
>   "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
>   ".       create a merge commit using the original merge commit's\n"
>   ".       message (or the oneline, if no original merge commit was\n"
>   ".       specified). Use -c <commit> to reword the commit message.\n"
>   "\n"
>   "These lines can be re-ordered; they are executed from top to bottom.\n"
>   msgstr ""
>   "\n"
>   "Befehle:\n"
> -"p, pick = Commit verwenden\n"
> -"r, reword = Commit verwenden, aber Commit-Beschreibung bearbeiten\n"
> -"e, edit = Commit verwenden, aber zum Nachbessern anhalten\n"
> -"s, squash = Commit verwenden, aber mit vorherigem Commit vereinen\n"
> -"f, fixup = wie \"squash\", aber diese Commit-Beschreibung verwerfen\n"
> -"x, exec = Befehl (Rest der Zeile) mittels Shell ausführen\n"
> -"d, drop = Commit entfernen\n"
> +"p, pick <Commit> = Commit verwenden\n"
> +"r, reword <Commit> = Commit verwenden, aber Commit-Beschreibung bearbeiten\n"
> +"e, edit <Commit> = Commit verwenden, aber zum Nachbessern anhalten\n"
> +"s, squash <Commit> = Commit verwenden, aber mit vorherigem Commit vereinen\n"
> +"f, fixup <Commit> = wie \"squash\", aber diese Commit-Beschreibung verwerfen\n"
> +"x, exec <Commit> = Befehl (Rest der Zeile) mittels Shell ausführen\n"
> +"d, drop <Commit> = Commit entfernen\n"
> +"l, label <Label> = aktuellen HEAD mit Label versehen\n"
> +"t, reset <Label> = HEAD zu einem Label umsetzen\n"
> +"m, merge [-C <Commit> | -c <Commit>] <Label> [# <eineZeile>]\n"
> +".       Merge-Commit mit der originalen Merge-Commit-Beschreibung erstellen\n"
> +".       (oder die eine Zeile, wenn keine originale Merge-Commit-Beschreibung\n"
> +".       spezifiziert ist). Benutzen Sie -c <Commit> zum Bearbeiten der\n"
> +".       Commit-Beschreibung.\n"
>   "\n"
>   "Diese Zeilen können umsortiert werden; Sie werden von oben nach unten\n"
>   "ausgeführt.\n"
>   
>   #: git-rebase--interactive.sh:179
>   msgid ""
>   "\n"
>   "Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
>   msgstr ""
>   "\n"
>   "Keine Zeile entfernen. Benutzen Sie 'drop', um explizit einen Commit zu\n"
> @@ -16997,32 +17013,32 @@ msgstr "Konnte temporäres Verzeichnis $state_dir nicht erstellen."
>   msgid "Could not mark as interactive"
>   msgstr "Konnte nicht als interaktiven Rebase markieren."
>   
>   #: git-rebase--interactive.sh:915
>   #, sh-format
>   msgid "Rebase $shortrevisions onto $shortonto ($todocount command)"
>   msgid_plural "Rebase $shortrevisions onto $shortonto ($todocount commands)"
>   msgstr[0] "Rebase von $shortrevisions auf $shortonto ($todocount Kommando)"
>   msgstr[1] "Rebase von $shortrevisions auf $shortonto ($todocount Kommandos)"
>   
>   #: git-rebase--interactive.sh:920
> -#, fuzzy
>   msgid ""
>   "\n"
>   "\tHowever, if you remove everything, the rebase will be aborted.\n"
>   "\n"
>   "\t"
>   msgstr ""
>   "\n"
> -"Wenn Sie jedoch alles löschen, wird der Rebase abgebrochen.\n"
> +"\tWenn Sie jedoch alles löschen, wird der Rebase abgebrochen.\n"
>   "\n"
> +"\t"
>   
>   #: git-rebase--interactive.sh:927
>   msgid "Note that empty commits are commented out"
>   msgstr "Leere Commits sind auskommentiert."
>   
>   #: git-rebase--interactive.sh:980
>   msgid "Could not generate todo list"
>   msgstr "Konnte TODO-Liste nicht erzeugen."
>   
>   #: git-rebase--interactive.sh:1001 git-rebase--interactive.sh:1006
>   msgid "Could not init rewritten commits"
> @@ -17899,25 +17915,24 @@ msgstr ""
>   "\n"
>   "    Für weitere Informationen, führen Sie 'git send-email --help' aus.\n"
>   "    Um das aktuelle Verhalten beizubehalten, aber diese Meldung zu "
>   "unterdrücken,\n"
>   "    führen Sie 'git config --global sendemail.confirm auto' aus.\n"
>   "\n"
>   
>   #. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
>   #. translation. The program will only accept English input
>   #. at this point.
>   #: git-send-email.perl:1415
> -#, fuzzy
>   msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
> -msgstr "Diese E-Mail versenden? (Ja [y]|Nein [n]|Beenden [q]|Alle [a]): "
> +msgstr "Diese E-Mail versenden? (Ja [y]|Nein [n]|Bearbeiten [e]|Beenden [q]|Alle [a]): "
>   
>   #: git-send-email.perl:1418
>   msgid "Send this email reply required"
>   msgstr "Zum Versenden dieser E-Mail ist eine Antwort erforderlich."
>   
>   #: git-send-email.perl:1446
>   msgid "The required SMTP server is not properly defined."
>   msgstr "Der erforderliche SMTP-Server ist nicht korrekt definiert."
>   
>   #: git-send-email.perl:1493
>   #, perl-format
> 

^ permalink raw reply	[relevance 0%]

* [PATCH] l10n: de.po: translate 108 new messages
@ 2018-07-19 17:15  1% Ralf Thielow
  2018-07-23 19:12  0% ` Matthias Rüster
  0 siblings, 1 reply; 200+ results
From: Ralf Thielow @ 2018-07-19 17:15 UTC (permalink / raw)
  To: Matthias Rüster, Phillip Szelat; +Cc: git, Ralf Thielow

Translate 108 new messages came from git.pot update in 9b7388a85 (l10n:
git.pot: v2.18.0 round 1 (108 new, 14 removed)).

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 po/de.po | 373 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 194 insertions(+), 179 deletions(-)

diff --git a/po/de.po b/po/de.po
index bdc5830e1..47986814c 100644
--- a/po/de.po
+++ b/po/de.po
@@ -10,25 +10,25 @@ msgstr ""
 "POT-Creation-Date: 2018-05-31 23:32+0800\n"
 "PO-Revision-Date: 2016-11-28 18:10+0100\n"
 "Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n"
 "Language-Team: German <>\n"
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n!=1);\n"
 
 #: advice.c:92
-#, fuzzy, c-format
+#, c-format
 msgid "%shint: %.*s%s\n"
-msgstr "Hinweis: %.*s\n"
+msgstr "%sHinweis: %.*s%s\n"
 
 #: advice.c:137
 msgid "Cherry-picking is not possible because you have unmerged files."
 msgstr ""
 "Cherry-Picken ist nicht möglich, weil Sie nicht zusammengeführte Dateien "
 "haben."
 
 #: advice.c:139
 msgid "Committing is not possible because you have unmerged files."
 msgstr ""
 "Committen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
@@ -1284,44 +1284,52 @@ msgstr "%s %s ist kein Commit!"
 #: commit.c:182
 msgid ""
 "Support for <GIT_DIR>/info/grafts is deprecated\n"
 "and will be removed in a future Git version.\n"
 "\n"
 "Please use \"git replace --convert-graft-file\"\n"
 "to convert the grafts into replace refs.\n"
 "\n"
 "Turn this message off by running\n"
 "\"git config advice.graftFileDeprecated false\""
 msgstr ""
+"Die Unterstützung für <GIT_DIR>/info/grafts ist veraltet\n"
+"und wird in zukünftigen Git Versionen entfernt.\n"
+"\n"
+"Bitte benutzen Sie \"git replace --convert-graft-file\"\n"
+"zum Konvertieren der künstlichen Vorgänger (\"grafts\")\n"
+"in ersetzende Referenzen.<\n"
+"\n"
+"Sie können diese Meldung unterdrücken, indem Sie\n"
+"\"git config advice.graftFileDeprecated false\" ausführen."
 
 #: commit.c:1537
 msgid ""
 "Warning: commit message did not conform to UTF-8.\n"
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitencoding to the encoding your project uses.\n"
 msgstr ""
 "Warnung: Die Commit-Beschreibung ist nicht UTF-8 konform.\n"
 "Sie können das nachbessern, nachdem Sie die Beschreibung korrigiert haben,\n"
 "oder Sie setzen die Konfigurationsvariable i18n.commitencoding auf das "
 "Encoding,\n"
 "welches von ihrem Projekt verwendet wird.\n"
 
 #: commit-graph.c:669
 #, c-format
 msgid "the commit graph format cannot write %d commits"
-msgstr ""
+msgstr "Das Commit-Graph Format kann nicht %d Commits schreiben."
 
 #: commit-graph.c:696
-#, fuzzy
 msgid "too many commits to write graph"
-msgstr "nur Commits anzeigen, die sich nicht im ersten Branch befinden"
+msgstr "Zu viele Commits zum Schreiben des Graphen."
 
 #: commit-graph.c:707 builtin/init-db.c:516 builtin/init-db.c:521
 #, c-format
 msgid "cannot mkdir %s"
 msgstr "kann Verzeichnis %s nicht erstellen"
 
 #: compat/obstack.c:405 compat/obstack.c:407
 msgid "memory exhausted"
 msgstr "Speicher verbraucht"
 
 #: config.c:187
@@ -1554,56 +1562,61 @@ msgstr "LF würde in %s durch CRLF ersetzt werden."
 msgid ""
 "LF will be replaced by CRLF in %s.\n"
 "The file will have its original line endings in your working directory."
 msgstr ""
 "LF wird in %s durch CRLF ersetzt.\n"
 "Die Datei wird ihre ursprünglichen Zeilenenden im Arbeitsverzeichnis "
 "behalten."
 
 #: convert.c:279
 #, c-format
 msgid "BOM is prohibited in '%s' if encoded as %s"
-msgstr ""
+msgstr "BOM ist in '%s' unzulässig, wenn als %s codiert."
 
 #: convert.c:286
 #, c-format
 msgid ""
 "The file '%s' contains a byte order mark (BOM). Please use UTF-%s as working-"
 "tree-encoding."
 msgstr ""
+"Die Datei '%s' enthält ein Byte-Order-Mark (BOM). Bitte benutzen Sie UTF-%s\n"
+"als Codierung im Arbeitsverzeichnis."
 
 #: convert.c:304
 #, c-format
 msgid "BOM is required in '%s' if encoded as %s"
-msgstr ""
+msgstr "BOM ist erforderlich in '%s', wenn als %s codiert."
 
 #: convert.c:306
 #, c-format
 msgid ""
 "The file '%s' is missing a byte order mark (BOM). Please use UTF-%sBE or UTF-"
 "%sLE (depending on the byte order) as working-tree-encoding."
 msgstr ""
+"Der Datei '%s' fehlt ein Byte-Order-Mark (BOM). Bitte benutzen Sie UTF-%sBE\n"
+"oder UTF-%sLE (abhängig von der Byte-Reihenfolge) als Codierung im\n"
+"Arbeitsverzeichnis."
 
 #: convert.c:424
-#, fuzzy, c-format
+#, c-format
 msgid "failed to encode '%s' from %s to %s"
-msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
+msgstr "Fehler beim Codieren von '%s' von %s nach %s."
 
 #: convert.c:467
 #, c-format
 msgid "encoding '%s' from %s to %s and back is not the same"
-msgstr ""
+msgstr "Die Codierung '%s' von %s nach %s und zurück ist nicht dasselbe."
 
 #: convert.c:1225
 msgid "true/false are no valid working-tree-encodings"
-msgstr ""
+msgstr "true/false sind keine gültigen Codierungen im Arbeitsverzeichnis."
 
 #: date.c:116
 msgid "in the future"
 msgstr "in der Zukunft"
 
 #: date.c:122
 #, c-format
 msgid "%<PRIuMAX> second ago"
 msgid_plural "%<PRIuMAX> seconds ago"
 msgstr[0] "vor %<PRIuMAX> Sekunde"
 msgstr[1] "vor %<PRIuMAX> Sekunden"
@@ -1970,25 +1983,24 @@ msgid "Server does not support --deepen"
 msgstr "Server unterstützt kein --deepen"
 
 #: fetch-pack.c:1065
 msgid "no common commits"
 msgstr "keine gemeinsamen Commits"
 
 #: fetch-pack.c:1077 fetch-pack.c:1414
 msgid "git fetch-pack: fetch failed."
 msgstr "git fetch-pack: Abholen fehlgeschlagen."
 
 #: fetch-pack.c:1199
-#, fuzzy
 msgid "Server does not support shallow requests"
-msgstr "Server unterstützt keine shallow-Clients"
+msgstr "Server unterstützt keine shallow-Anfragen."
 
 #: fetch-pack.c:1584
 msgid "no matching remote head"
 msgstr "kein übereinstimmender Remote-Branch"
 
 #: fetch-pack.c:1610
 #, c-format
 msgid "no such remote ref %s"
 msgstr "keine solche Remote-Referenz %s"
 
 #: fetch-pack.c:1613
@@ -2212,30 +2224,32 @@ msgstr "Lesen des Zwischenspeichers fehlgeschlagen"
 
 #: merge.c:136 builtin/am.c:1946 builtin/am.c:1980 builtin/checkout.c:378
 #: builtin/checkout.c:606 builtin/clone.c:761
 msgid "unable to write new index file"
 msgstr "Konnte neue Index-Datei nicht schreiben."
 
 #: merge-recursive.c:298
 msgid "(bad commit)\n"
 msgstr "(ungültiger Commit)\n"
 
 #: merge-recursive.c:320
-#, fuzzy, c-format
+#, c-format
 msgid "add_cacheinfo failed for path '%s'; merge aborting."
-msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen"
+msgstr "add_cacheinfo für Pfad '%s' fehlgeschlagen; Merge wird abgebrochen."
 
 #: merge-recursive.c:328
-#, fuzzy, c-format
+#, c-format
 msgid "add_cacheinfo failed to refresh for path '%s'; merge aborting."
-msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen"
+msgstr ""
+"add_cacheinfo zur Aktualisierung für Pfad '%s' fehlgeschlagen;\n"
+"Merge wird abgebrochen."
 
 #: merge-recursive.c:410
 msgid "error building trees"
 msgstr "Fehler beim Erstellen der \"Tree\"-Objekte"
 
 #: merge-recursive.c:881
 #, c-format
 msgid "failed to create path '%s'%s"
 msgstr "Fehler beim Erstellen des Pfades '%s'%s"
 
 #: merge-recursive.c:892
@@ -2270,94 +2284,101 @@ msgstr "Fehler beim Öffnen von '%s': %s"
 #: merge-recursive.c:994
 #, c-format
 msgid "failed to symlink '%s': %s"
 msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s': %s"
 
 #: merge-recursive.c:999
 #, c-format
 msgid "do not know what to do with %06o %s '%s'"
 msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
 
 #: merge-recursive.c:1186
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to merge submodule %s (not checked out)"
-msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
+msgstr "Fehler beim Merge von Submodul %s (nicht ausgecheckt)."
 
 #: merge-recursive.c:1193
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to merge submodule %s (commits not present)"
-msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
+msgstr "Fehler beim Merge von Submodul %s (Commits nicht vorhanden)."
 
 #: merge-recursive.c:1200
 #, c-format
 msgid "Failed to merge submodule %s (commits don't follow merge-base)"
-msgstr ""
+msgstr "Fehler beim Merge von Submodul %s (Commits folgen keiner Merge-Basis)"
 
 #: merge-recursive.c:1208 merge-recursive.c:1220
 #, c-format
 msgid "Fast-forwarding submodule %s to the following commit:"
-msgstr ""
+msgstr "Spule Submodul %s zu dem folgenden Commit vor:"
 
 #: merge-recursive.c:1211 merge-recursive.c:1223
-#, fuzzy, c-format
+#, c-format
 msgid "Fast-forwarding submodule %s to %s"
-msgstr "Spule vor zu $sha1"
+msgstr "Spule Submodul %s vor zu %s"
 
 #: merge-recursive.c:1245
 #, c-format
 msgid "Failed to merge submodule %s (merge following commits not found)"
-msgstr ""
+msgstr "Fehler beim Merge von Submodule %s (dem Merge nachfolgende Commits nicht gefunden)"
 
 #: merge-recursive.c:1249
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to merge submodule %s (not fast-forward)"
-msgstr "Fehler beim Eintragen von Submodul '$sm_path' in die Konfiguration."
+msgstr "Fehler beim Merge von Submodul %s (kein Vorspulen)"
 
 #: merge-recursive.c:1250
 msgid "Found a possible merge resolution for the submodule:\n"
-msgstr ""
+msgstr "Mögliche Auflösung des Merges für Submodul gefunden:\n"
 
 #: merge-recursive.c:1253
 #, c-format
 msgid ""
 "If this is correct simply add it to the index for example\n"
 "by using:\n"
 "\n"
 "  git update-index --cacheinfo 160000 %s \"%s\"\n"
 "\n"
 "which will accept this suggestion.\n"
 msgstr ""
+"Falls das korrekt ist, fügen Sie es einfach der Staging-Area, zum Beispiel mit:\n"
+"\n"
+"  git update-index --cacheinfo 160000 %s \"%s\"\n"
+"\n"
+"hinzu, um diesen Vorschlag zu akzeptieren.\n"
 
 #: merge-recursive.c:1262
 #, c-format
 msgid "Failed to merge submodule %s (multiple merges found)"
-msgstr ""
+msgstr "Fehler beim Merge von Submodul %s (mehrere Merges gefunden)"
 
 #: merge-recursive.c:1321
 msgid "Failed to execute internal merge"
 msgstr "Fehler bei Ausführung des internen Merges"
 
 #: merge-recursive.c:1326
 #, c-format
 msgid "Unable to add %s to database"
 msgstr "Konnte %s nicht zur Datenbank hinzufügen"
 
 #: merge-recursive.c:1358
 #, c-format
 msgid "Auto-merging %s"
 msgstr "automatischer Merge von %s"
 
 #: merge-recursive.c:1423
-#, fuzzy, c-format
+#, c-format
 msgid "Error: Refusing to lose untracked file at %s; writing to %s instead."
-msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
+msgstr ""
+"Fehler: Verweigere unversionierte Datei bei %s zu verlieren;\n"
+"schreibe stattdessen nach %s."
 
 #: merge-recursive.c:1475
 #, c-format
 msgid ""
 "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
 "in tree."
 msgstr ""
 "KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde "
 "im Arbeitsbereich gelassen."
 
 #: merge-recursive.c:1480
@@ -2389,35 +2410,35 @@ msgstr ""
 
 #: merge-recursive.c:1526
 msgid "rename"
 msgstr "umbenennen"
 
 #: merge-recursive.c:1526
 msgid "renamed"
 msgstr "umbenannt"
 
 #: merge-recursive.c:1580 merge-recursive.c:1736 merge-recursive.c:2368
 #: merge-recursive.c:3086
-#, fuzzy, c-format
+#, c-format
 msgid "Refusing to lose dirty file at %s"
-msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
+msgstr "Verweigere geänderte Datei bei %s zu verlieren."
 
 #: merge-recursive.c:1594
 #, c-format
 msgid "%s is a directory in %s adding as %s instead"
 msgstr "%s ist ein Verzeichnis in %s, füge es stattdessen als %s hinzu"
 
 #: merge-recursive.c:1599
-#, fuzzy, c-format
+#, c-format
 msgid "Refusing to lose untracked file at %s; adding as %s instead"
-msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
+msgstr "Verweigere unversionierte Datei bei %s zu verlieren; füge stattdessen %s hinzu"
 
 #: merge-recursive.c:1625
 #, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
 "\"->\"%s\" in \"%s\"%s"
 msgstr ""
 "KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Branch \"%s\" "
 "und \"%s\"->\"%s\" in Branch \"%s\"%s"
 
 #: merge-recursive.c:1630
@@ -2429,63 +2450,72 @@ msgstr " (bleibt unaufgelöst)"
 msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
 msgstr ""
 "KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s "
 "in %s"
 
 #: merge-recursive.c:1733
 #, c-format
 msgid "Renaming %s to %s and %s to %s instead"
 msgstr "Benenne stattdessen %s nach %s und %s nach %s um"
 
 #: merge-recursive.c:1745
-#, fuzzy, c-format
+#, c-format
 msgid "Refusing to lose untracked file at %s, even though it's in the way."
-msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
+msgstr "Verweigere unversionierte Datei bei %s zu verlieren, auch wenn diese im Weg ist."
 
 #: merge-recursive.c:1951
 #, c-format
 msgid ""
 "CONFLICT (directory rename split): Unclear where to place %s because "
 "directory %s was renamed to multiple other directories, with no destination "
 "getting a majority of the files."
 msgstr ""
+"KONFLIKT (Aufteilung Verzeichnisumbenennung): Unklar, wo %s zu platzieren ist,\n"
+"weil Verzeichnis %s zu mehreren anderen Verzeichnissen umbenannt wurde, wobei\n"
+"keines dieser Ziele die Mehrheit der Dateien erhielt."
 
 #: merge-recursive.c:1983
 #, c-format
 msgid ""
 "CONFLICT (implicit dir rename): Existing file/dir at %s in the way of "
 "implicit directory rename(s) putting the following path(s) there: %s."
 msgstr ""
+"KONFLIKT (implizite Verzeichnisumbenennung): Existierende Datei/Pfad bei %s im\n"
+"Weg von impliziter Verzeichnisumbenennung, die versucht, einen oder mehrere\n"
+"Pfade dahin zu setzen: %s."
 
 #: merge-recursive.c:1993
 #, c-format
 msgid ""
 "CONFLICT (implicit dir rename): Cannot map more than one path to %s; "
 "implicit directory renames tried to put these paths there: %s"
 msgstr ""
+"KONFLIKT (implizite Verzeichnisumbenennung): Kann nicht mehr als ein Pfad zu\n"
+"%s mappen; implizite Verzeichnisumbenennungen versuchten diese Pfade dahin\n"
+"zu setzen: %s"
 
 #: merge-recursive.c:2085
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "CONFLICT (rename/rename): Rename directory %s->%s in %s. Rename directory %s-"
 ">%s in %s"
 msgstr ""
-"KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s "
-"in %s"
+"KONFLIKT (umbenennen/umbenennen): Benenne Verzeichnis um %s->%s in %s.\n"
+"Benenne Verzeichnis um %s->%s in %s"
 
 #: merge-recursive.c:2330
 #, c-format
 msgid ""
 "WARNING: Avoiding applying %s -> %s rename to %s, because %s itself was "
 "renamed."
-msgstr ""
+msgstr "WARNUNG: Vermeide Umbenennung %s -> %s von %s, weil %s selbst umbenannt wurde."
 
 #: merge-recursive.c:2736
 #, c-format
 msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
 msgstr ""
 "KONFLIKT (umbenennen/hinzufügen): Benenne um %s->%s in %s. %s hinzugefügt in "
 "%s"
 
 #: merge-recursive.c:2751
 #, c-format
 msgid "Adding merged %s"
@@ -2682,25 +2712,25 @@ msgstr "      oder: %s"
 
 #: parse-options.c:649
 #, c-format
 msgid "    %s"
 msgstr "    %s"
 
 #: parse-options.c:688
 msgid "-NUM"
 msgstr "-NUM"
 
 #: parse-options-cb.c:44
-#, fuzzy, c-format
+#, c-format
 msgid "malformed expiration date '%s'"
-msgstr "Fehlerhaftes Optionsblatt: '%s'"
+msgstr "Fehlerhaftes Ablaufdatum '%s'"
 
 #: parse-options-cb.c:112
 #, c-format
 msgid "malformed object name '%s'"
 msgstr "fehlerhafter Objekt-Name '%s'"
 
 #: path.c:892
 #, c-format
 msgid "Could not make %s writable by group"
 msgstr "Konnte Gruppenschreibrecht für %s nicht setzen."
 
@@ -3012,25 +3042,25 @@ msgstr "Format: %%(end) Atom ohne zugehöriges Atom verwendet"
 #: ref-filter.c:779
 #, c-format
 msgid "malformed format string %s"
 msgstr "Fehlerhafter Formatierungsstring %s"
 
 #: ref-filter.c:1387
 #, c-format
 msgid "(no branch, rebasing %s)"
 msgstr "(kein Branch, Rebase von Branch %s im Gange)"
 
 #: ref-filter.c:1390
-#, fuzzy, c-format
+#, c-format
 msgid "(no branch, rebasing detached HEAD %s)"
-msgstr "(kein Branch, Rebase von Branch %s im Gange)"
+msgstr "(kein Branch, Rebase von losgelöstem HEAD %s)"
 
 #: ref-filter.c:1393
 #, c-format
 msgid "(no branch, bisect started on %s)"
 msgstr "(kein Branch, binäre Suche begonnen bei %s)"
 
 #. TRANSLATORS: make sure this matches "HEAD
 #. detached at " in wt-status.c
 #.
 #: ref-filter.c:1401
 #, c-format
@@ -3283,25 +3313,25 @@ msgstr "die Gegenseite unterstützt keinen atomaren Versand (\"--atomic push\")"
 
 #: send-pack.c:440
 msgid "the receiving end does not support push options"
 msgstr "die Gegenseite unterstützt keine Push-Optionen"
 
 #: sequencer.c:174
 #, c-format
 msgid "invalid commit message cleanup mode '%s'"
 msgstr "Ungültiger \"cleanup\"-Modus '%s' für Commit-Beschreibungen."
 
 #: sequencer.c:274
-#, fuzzy, c-format
+#, c-format
 msgid "could not delete '%s'"
-msgstr "Konnte %s nicht entfernen"
+msgstr "Konnte '%s' nicht löschen."
 
 #: sequencer.c:300
 msgid "revert"
 msgstr "Revert"
 
 #: sequencer.c:302
 msgid "cherry-pick"
 msgstr "Cherry-Pick"
 
 #: sequencer.c:304
 msgid "rebase -i"
@@ -3414,25 +3444,24 @@ msgstr ""
 "  git commit --amend %s\n"
 "\n"
 "Wenn daraus ein neuer Commit erzeugt werden soll, führen Sie aus:\n"
 "\n"
 "  git commit %s\n"
 "\n"
 "Im Anschluss führen Sie zum Fortfahren aus:\n"
 "\n"
 "  git rebase --continue\n"
 
 #: sequencer.c:817
-#, fuzzy
 msgid "writing root commit"
-msgstr "nichts zu committen\n"
+msgstr "Root-Commit schreiben"
 
 #: sequencer.c:1042
 msgid "'prepare-commit-msg' hook failed"
 msgstr "'prepare-commit-msg' Hook fehlgeschlagen."
 
 #: sequencer.c:1049
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
 "You can suppress this message by setting them explicitly. Run the\n"
 "following command and follow the instructions in your editor to edit\n"
@@ -3588,25 +3617,24 @@ msgstr "Die Commit-Beschreibung #%d wird ausgelassen:"
 
 #: sequencer.c:1552
 #, c-format
 msgid "unknown command: %d"
 msgstr "Unbekannter Befehl: %d"
 
 #: sequencer.c:1630
 msgid "your index file is unmerged."
 msgstr "Ihre Index-Datei ist nicht zusammengeführt."
 
 #: sequencer.c:1637
-#, fuzzy
 msgid "cannot fixup root commit"
-msgstr "kann Commit %s (%s) nicht finden"
+msgstr "kann fixup nicht auf Root-Commit anwenden"
 
 #: sequencer.c:1656
 #, c-format
 msgid "commit %s is a merge but no -m option was given."
 msgstr "Commit %s ist ein Merge, aber die Option -m wurde nicht angegeben."
 
 #: sequencer.c:1664
 #, c-format
 msgid "commit %s does not have parent %d"
 msgstr "Commit %s hat keinen Eltern-Commit %d"
 
@@ -3707,23 +3735,23 @@ msgstr "Kann Revert nicht während eines Cherry-Picks ausführen."
 #, c-format
 msgid "invalid key: %s"
 msgstr "Ungültiger Schlüssel: %s"
 
 #: sequencer.c:2197
 #, c-format
 msgid "invalid value for %s: %s"
 msgstr "Ungültiger Wert für %s: %s"
 
 #: sequencer.c:2268
 msgid "unusable squash-onto"
-msgstr ""
+msgstr "Unbenutzbares squash-onto."
 
 #: sequencer.c:2284
 #, c-format
 msgid "malformed options sheet: '%s'"
 msgstr "Fehlerhaftes Optionsblatt: '%s'"
 
 #: sequencer.c:2322
 msgid "a cherry-pick or revert is already in progress"
 msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang"
 
 #: sequencer.c:2323
@@ -3824,69 +3852,65 @@ msgid ""
 "\n"
 msgstr ""
 "Ausführung erfolgreich: %s\n"
 "Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
 "Führen Sie dann aus:\n"
 "\n"
 "  git rebase --continue\n"
 "\n"
 
 #: sequencer.c:2770
-#, fuzzy
 msgid "writing fake root commit"
-msgstr "nichts zu committen\n"
+msgstr "unechten Root-Commit schreiben"
 
 #: sequencer.c:2775
 msgid "writing squash-onto"
-msgstr ""
+msgstr "squash-onto schreiben"
 
 #: sequencer.c:2810
-#, fuzzy, c-format
+#, c-format
 msgid "failed to find tree of %s"
 msgstr "Fehler beim Finden des \"Tree\"-Objektes von %s."
 
 #: sequencer.c:2828
-#, fuzzy
 msgid "could not write index"
-msgstr "Konnte den Index nicht lesen."
+msgstr "Konnte Index nicht schreiben."
 
 #: sequencer.c:2860
-#, fuzzy
 msgid "cannot merge without a current revision"
-msgstr "Kann '%s' nicht ohne vorherigen Commit ausführen"
+msgstr "Kann nicht ohne einen aktuellen Commit mergen."
 
 #: sequencer.c:2883
-#, fuzzy, c-format
+#, c-format
 msgid "could not resolve '%s'"
-msgstr "Konnte '%s' nicht löschen"
+msgstr "Konnte '%s' nicht auflösen."
 
 #: sequencer.c:2905
-#, fuzzy, c-format
+#, c-format
 msgid "could not get commit message of '%s'"
-msgstr "Konnte Commit-Beschreibung von %s nicht lesen."
+msgstr "Konnte keine Commit-Beschreibung von '%s' bekommen."
 
 #: sequencer.c:2915 sequencer.c:2940
-#, fuzzy, c-format
+#, c-format
 msgid "could not write '%s'"
-msgstr "Konnte nicht nach '%s' schreiben."
+msgstr "Konnte '%s' nicht schreiben."
 
 #: sequencer.c:3004
-#, fuzzy, c-format
+#, c-format
 msgid "could not even attempt to merge '%.*s'"
-msgstr "konnte '%s' nicht öffnen oder lesen"
+msgstr "Konnte nicht einmal versuchen '%.*s' zu mergen."
 
 #: sequencer.c:3020
-#, fuzzy
 msgid "merge: Unable to write new index file"
-msgstr "%s: Konnte neue Index-Datei nicht schreiben"
+msgstr "merge: Konnte neue Index-Datei nicht schreiben."
 
 #: sequencer.c:3087
 #, c-format
 msgid "Applied autostash.\n"
 msgstr "Automatischen Stash angewendet.\n"
 
 #: sequencer.c:3099
 #, c-format
 msgid "cannot store %s"
 msgstr "kann %s nicht speichern"
 
@@ -3905,22 +3929,30 @@ msgstr ""
 #, c-format
 msgid ""
 "Could not execute the todo command\n"
 "\n"
 "    %.*s\n"
 "It has been rescheduled; To edit the command before continuing, please\n"
 "edit the todo list first:\n"
 "\n"
 "    git rebase --edit-todo\n"
 "    git rebase --continue\n"
 msgstr ""
+"Konnte TODO-Befehl nicht ausführen\n"
+"\n"
+"    %.*s\n"
+"Dieser wurde neu angesetzt; Um den Befehl zu bearbeiten, bevor fortgesetzt wird,\n"
+"bearbeiten Sie bitte zuerst die TODO-Liste:\n"
+"\n"
+"    git rebase --edit-todo\n"
+"    git rebase --continue\n"
 
 #: sequencer.c:3201
 #, c-format
 msgid "Stopped at %s...  %.*s\n"
 msgstr "Angehalten bei %s... %.*s\n"
 
 #: sequencer.c:3263
 #, c-format
 msgid "unknown command %d"
 msgstr "Unbekannter Befehl %d"
 
@@ -3961,25 +3993,25 @@ msgstr "Ungültige Inhalte: '%s'"
 msgid ""
 "\n"
 "You have uncommitted changes in your working tree. Please, commit them\n"
 "first and then run 'git rebase --continue' again."
 msgstr ""
 "\n"
 "Sie haben nicht committete Änderungen in Ihrem Arbeitsverzeichnis. Bitte\n"
 "committen Sie diese zuerst und führen Sie dann 'git rebase --continue'\n"
 "erneut aus."
 
 #: sequencer.c:3454 sequencer.c:3492
-#, fuzzy, c-format
+#, c-format
 msgid "could not write file: '%s'"
-msgstr "konnte Datei '%s' nicht erstellen"
+msgstr "Konnte Datei nicht schreiben: '%s'"
 
 #: sequencer.c:3507
 msgid "could not remove CHERRY_PICK_HEAD"
 msgstr "Konnte CHERRY_PICK_HEAD nicht löschen."
 
 #: sequencer.c:3514
 msgid "could not commit staged changes."
 msgstr "Konnte Änderungen aus der Staging-Area nicht committen."
 
 #: sequencer.c:3611
 #, c-format
@@ -4388,25 +4420,25 @@ msgstr "Fehler bei Rekursion in Submodul-Pfad '%s'"
 
 #: submodule.c:1863
 msgid "could not start ls-files in .."
 msgstr "Konnte 'ls-files' nicht in .. starten"
 
 #: submodule.c:1902
 #, c-format
 msgid "ls-tree returned unexpected return code %d"
 msgstr "ls-tree mit unerwartetem Rückgabewert %d beendet"
 
 #: submodule-config.c:230
-#, fuzzy, c-format
+#, c-format
 msgid "ignoring suspicious submodule name: %s"
-msgstr "Ignoriere Referenz mit fehlerhaftem Namen %s"
+msgstr "Ignoriere verdächtigen Submodulnamen: %s"
 
 #: submodule-config.c:294
 msgid "negative values not allowed for submodule.fetchjobs"
 msgstr "Negative Werte für submodule.fetchjobs nicht erlaubt."
 
 #: submodule-config.c:467
 #, c-format
 msgid "invalid value for %s"
 msgstr "Ungültiger Wert für %s"
 
 #: trailer.c:238
@@ -4466,25 +4498,24 @@ msgstr "konnte temporäre Datei nicht zu %s umbenennen"
 #: transport.c:116
 #, c-format
 msgid "Would set upstream of '%s' to '%s' of '%s'\n"
 msgstr "Würde Upstream-Branch von '%s' zu '%s' von '%s' setzen\n"
 
 #: transport.c:208
 #, c-format
 msgid "transport: invalid depth option '%s'"
 msgstr "transport: ungültige --depth Option '%s'"
 
 #: transport.c:584
-#, fuzzy
 msgid "could not parse transport.color.* config"
-msgstr "konnte Autor-Skript nicht parsen"
+msgstr "Konnte transport.color.* Konfiguration nicht parsen."
 
 #: transport.c:996
 #, c-format
 msgid ""
 "The following submodule paths contain changes that can\n"
 "not be found on any remote:\n"
 msgstr ""
 "Die folgenden Submodul-Pfade enthalten Änderungen, die in keinem\n"
 "Remote-Repository gefunden wurden:\n"
 
 #: transport.c:1000
@@ -6090,51 +6121,50 @@ msgid "--bisect-clean-state requires no arguments"
 msgstr "--bisect-clean-state erwartet keine Argumente."
 
 #: builtin/blame.c:29
 msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
 msgstr "git blame [<Optionen>] [<rev-opts>] [<Commit>] [--] <Datei>"
 
 #: builtin/blame.c:34
 msgid "<rev-opts> are documented in git-rev-list(1)"
 msgstr "<rev-opts> sind dokumentiert in git-rev-list(1)"
 
 #: builtin/blame.c:404
-#, fuzzy, c-format
+#, c-format
 msgid "expecting a color: %s"
-msgstr "Formatfarben beachten"
+msgstr "Erwarte eine Farbe: %s"
 
 #: builtin/blame.c:411
 msgid "must end with a color"
-msgstr ""
+msgstr "Muss mit einer Farbe enden."
 
 #: builtin/blame.c:697
-#, fuzzy, c-format
+#, c-format
 msgid "invalid color '%s' in color.blame.repeatedLines"
-msgstr "Ignoriere ungültige Farbe '%.*s' in log.graphColors"
+msgstr "Ungültige Farbe '%s' in color.blame.repeatedLines."
 
 #: builtin/blame.c:715
-#, fuzzy
 msgid "invalid value for blame.coloring"
-msgstr "Ungültiger Wert für --missing."
+msgstr "Ungültiger Wert für blame.coloring."
 
 #: builtin/blame.c:786
 msgid "Show blame entries as we find them, incrementally"
 msgstr "\"blame\"-Einträge schrittweise anzeigen, während wir sie generieren"
 
 #: builtin/blame.c:787
 msgid "Show blank SHA-1 for boundary commits (Default: off)"
 msgstr "leere SHA-1 für Grenz-Commits anzeigen (Standard: aus)"
 
 #: builtin/blame.c:788
 msgid "Do not treat root commits as boundaries (Default: off)"
-msgstr "Ursprungs-Commits nicht als Grenzen behandeln (Standard: aus)"
+msgstr "Root-Commits nicht als Grenzen behandeln (Standard: aus)"
 
 #: builtin/blame.c:789
 msgid "Show work cost statistics"
 msgstr "Statistiken zum Arbeitsaufwand anzeigen"
 
 #: builtin/blame.c:790
 msgid "Force progress reporting"
 msgstr "Fortschrittsanzeige erzwingen"
 
 #: builtin/blame.c:791
 msgid "Show output score for blame entries"
@@ -6177,27 +6207,27 @@ msgstr "Den Namen des Autors und den Zeitstempel unterdrücken (Standard: aus)"
 #: builtin/blame.c:800
 msgid "Show author email instead of name (Default: off)"
 msgstr ""
 "Anstatt des Namens die E-Mail-Adresse des Autors anzeigen (Standard: aus)"
 
 #: builtin/blame.c:801
 msgid "Ignore whitespace differences"
 msgstr "Unterschiede im Whitespace ignorieren"
 
 #: builtin/blame.c:802
 msgid "color redundant metadata from previous line differently"
-msgstr ""
+msgstr "redundante Metadaten der vorherigen Zeile unterschiedlich einfärben"
 
 #: builtin/blame.c:803
 msgid "color lines by age"
-msgstr ""
+msgstr "Zeilen nach Alter einfärben"
 
 #: builtin/blame.c:810
 msgid "Use an experimental heuristic to improve diffs"
 msgstr ""
 "eine experimentelle Heuristik zur Verbesserung der Darstellung\n"
 "von Unterschieden verwenden"
 
 #: builtin/blame.c:812
 msgid "Spend extra cycles to find better match"
 msgstr "Länger arbeiten, um bessere Übereinstimmungen zu finden"
 
@@ -8147,29 +8177,28 @@ msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
 msgstr ""
 "Änderungen in Submodulen ignorieren, optional wenn: all, dirty, untracked. "
 "(Standard: all)"
 
 #: builtin/commit.c:1329
 msgid "list untracked files in columns"
 msgstr "unversionierte Dateien in Spalten auflisten"
 
 #: builtin/commit.c:1330
-#, fuzzy
 msgid "do not detect renames"
-msgstr "keine Abfrage von Remote-Repositories"
+msgstr "keine Umbenennungen ermitteln"
 
 #: builtin/commit.c:1332
 msgid "detect renames, optionally set similarity index"
-msgstr ""
+msgstr "Umbenennungen erkennen, optional Index für Gleichheit setzen"
 
 #: builtin/commit.c:1352
 msgid "Unsupported combination of ignored and untracked-files arguments"
 msgstr ""
 "Nicht unterstützte Kombination von ignored und untracked-files Argumenten."
 
 #: builtin/commit.c:1450
 msgid "suppress summary after successful commit"
 msgstr "Zusammenfassung nach erfolgreichem Commit unterdrücken"
 
 #: builtin/commit.c:1451
@@ -8346,68 +8375,68 @@ msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full and quota is\n"
 "not exceeded, and then \"git reset HEAD\" to recover."
 msgstr ""
 "Das Repository wurde aktualisiert, aber die \"new_index\"-Datei\n"
 "konnte nicht geschrieben werden. Prüfen Sie, dass Ihre Festplatte nicht\n"
 "voll und Ihr Kontingent nicht aufgebraucht ist und führen Sie\n"
 "anschließend \"git reset HEAD\" zu Wiederherstellung aus."
 
 #: builtin/commit-graph.c:9
 msgid "git commit-graph [--object-dir <objdir>]"
-msgstr ""
+msgstr "git commit-graph [--object-dir <Objektverzeichnis>]"
 
 #: builtin/commit-graph.c:10 builtin/commit-graph.c:16
 msgid "git commit-graph read [--object-dir <objdir>]"
-msgstr ""
+msgstr "git commit-graph read [--object-dir <Objektverzeichnis>]"
 
 #: builtin/commit-graph.c:11 builtin/commit-graph.c:21
 msgid ""
 "git commit-graph write [--object-dir <objdir>] [--append] [--stdin-packs|--"
 "stdin-commits]"
-msgstr ""
+msgstr "git commit-graph write [--object-dir <Objektverzeichnis>] [--append] [--stdin-packs|--stdin-commits]"
 
 #: builtin/commit-graph.c:39 builtin/commit-graph.c:92
 #: builtin/commit-graph.c:147 builtin/fetch.c:161 builtin/log.c:1466
 msgid "dir"
 msgstr "Verzeichnis"
 
 #: builtin/commit-graph.c:40 builtin/commit-graph.c:93
 #: builtin/commit-graph.c:148
 msgid "The object directory to store the graph"
-msgstr ""
+msgstr "Das Objektverzeichnis zum Speichern des Graphen."
 
 #: builtin/commit-graph.c:95
 msgid "scan pack-indexes listed by stdin for commits"
-msgstr ""
+msgstr "durch Standard-Eingabe gelistete Pack-Indexe nach Commits scannen"
 
 #: builtin/commit-graph.c:97
 msgid "start walk at commits listed by stdin"
-msgstr ""
+msgstr "Lauf bei Commits beginnen, die über die Standard-Eingabe gelistet sind"
 
 #: builtin/commit-graph.c:99
 msgid "include all commits already in the commit-graph file"
-msgstr ""
+msgstr "alle Commits einschließen, die sich bereits in der Commit-Graph-Datei befinden"
 
 #: builtin/commit-graph.c:108
 msgid "cannot use both --stdin-commits and --stdin-packs"
-msgstr ""
+msgstr "Kann nicht --stdin-commits und --stdin-packs benutzen."
 
 #: builtin/config.c:10
 msgid "git config [<options>]"
 msgstr "git config [<Optionen>]"
 
 #: builtin/config.c:101
-#, fuzzy, c-format
+#, c-format
 msgid "unrecognized --type argument, %s"
-msgstr "nicht erkanntes Argument: %s"
+msgstr "nicht erkanntes --type Argument, %s"
 
 #: builtin/config.c:123
 msgid "Config file location"
 msgstr "Ort der Konfigurationsdatei"
 
 #: builtin/config.c:124
 msgid "use global config file"
 msgstr "globale Konfigurationsdatei verwenden"
 
 #: builtin/config.c:125
 msgid "use system config file"
@@ -8486,25 +8515,24 @@ msgid "find the color configured: slot [default]"
 msgstr "die konfigurierte Farbe finden: Slot [Standard]"
 
 #: builtin/config.c:143
 msgid "find the color setting: slot [stdout-is-tty]"
 msgstr "die Farbeinstellung finden: Slot [Standard-Ausgabe-ist-Terminal]"
 
 #: builtin/config.c:144
 msgid "Type"
 msgstr "Typ"
 
 #: builtin/config.c:145
-#, fuzzy
 msgid "value is given this type"
-msgstr "Wert ist ein Verfallsdatum"
+msgstr "Wert ist mit diesem Typ angegeben"
 
 #: builtin/config.c:146
 msgid "value is \"true\" or \"false\""
 msgstr "Wert ist \"true\" oder \"false\""
 
 #: builtin/config.c:147
 msgid "value is decimal number"
 msgstr "Wert ist eine Dezimalzahl"
 
 #: builtin/config.c:148
 msgid "value is --bool or --int"
@@ -8533,34 +8561,33 @@ msgstr "nur Variablennamen anzeigen"
 #: builtin/config.c:154
 msgid "respect include directives on lookup"
 msgstr "beachtet \"include\"-Direktiven beim Nachschlagen"
 
 #: builtin/config.c:155
 msgid "show origin of config (file, standard input, blob, command line)"
 msgstr ""
 "Ursprung der Konfiguration anzeigen (Datei, Standard-Eingabe, Blob, "
 "Befehlszeile)"
 
 #: builtin/config.c:156
-#, fuzzy
 msgid "value"
-msgstr "Schlüssel=Wert"
+msgstr "Wert"
 
 #: builtin/config.c:156
 msgid "with --get, use default value when missing entry"
-msgstr ""
+msgstr "mit --get, benutze den Standardwert, wenn der Eintrag fehlt"
 
 #: builtin/config.c:332
-#, fuzzy, c-format
+#, c-format
 msgid "failed to format default config value: %s"
-msgstr "Konnte Datei '%s' nicht erstellen"
+msgstr "Fehler beim Formatieren des Standardkonfigurationswertes: %s"
 
 #: builtin/config.c:431
 msgid "unable to parse default color value"
 msgstr "konnte Standard-Farbwert nicht parsen"
 
 #: builtin/config.c:575
 #, c-format
 msgid ""
 "# This is Git's per-user configuration file.\n"
 "[user]\n"
 "# Please adapt and uncomment the following lines:\n"
@@ -8570,25 +8597,24 @@ msgstr ""
 "# Das ist Git's benutzerspezifische Konfigurationsdatei.\n"
 "[user]\n"
 "# Bitte passen Sie die folgenden Zeilen an und kommentieren Sie diese aus:\n"
 "#\tname = %s\n"
 "#\temail = %s\n"
 
 #: builtin/config.c:603
 msgid "--local can only be used inside a git repository"
 msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
 
 #: builtin/config.c:606
-#, fuzzy
 msgid "--blob can only be used inside a git repository"
-msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
+msgstr "--blob kann nur innerhalb eines Git-Repositories verwendet werden."
 
 #: builtin/config.c:735
 #, c-format
 msgid "cannot create configuration file %s"
 msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
 
 #: builtin/config.c:748
 #, c-format
 msgid ""
 "cannot overwrite multiple values with a single value\n"
 "       Use a regexp, --add or --replace-all to change %s."
@@ -9147,24 +9173,24 @@ msgid "non-fast-forward"
 msgstr "kein Vorspulen"
 
 #: builtin/fetch.c:795
 #, c-format
 msgid "%s did not send all necessary objects\n"
 msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
 
 #: builtin/fetch.c:815
 #, c-format
 msgid "reject %s because shallow roots are not allowed to be updated"
 msgstr ""
-"%s wurde zurückgewiesen, da Ursprungs-Commits von Repositories mit "
-"unvollständiger Historie (shallow) nicht aktualisiert werden dürfen."
+"%s wurde zurückgewiesen, da Root-Commits von Repositories mit unvollständiger\n"
+"Historie (shallow) nicht aktualisiert werden dürfen."
 
 #: builtin/fetch.c:903 builtin/fetch.c:999
 #, c-format
 msgid "From %.*s\n"
 msgstr "Von %.*s\n"
 
 #: builtin/fetch.c:914
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
 " 'git remote prune %s' to remove any old, conflicting branches"
@@ -9464,33 +9490,33 @@ msgstr "mehr Gründlichkeit (erhöht Laufzeit)"
 msgid "enable auto-gc mode"
 msgstr "\"auto-gc\" Modus aktivieren"
 
 #: builtin/gc.c:508
 msgid "force running gc even if there may be another gc running"
 msgstr ""
 "Ausführung von \"git gc\" erzwingen, selbst wenn ein anderes\n"
 "\"git gc\" bereits ausgeführt wird"
 
 #: builtin/gc.c:511
 msgid "repack all other packs except the largest pack"
-msgstr ""
+msgstr "alle anderen Pakete, außer das größte Paket, neu packen"
 
 #: builtin/gc.c:528
-#, fuzzy, c-format
+#, c-format
 msgid "failed to parse gc.logexpiry value %s"
-msgstr "Fehler beim Parsen des Wertes '%s' von gc.logexpiry"
+msgstr "Fehler beim Parsen des Wertes '%s' von gc.logexpiry."
 
 #: builtin/gc.c:539
-#, fuzzy, c-format
+#, c-format
 msgid "failed to parse prune expiry value %s"
-msgstr "Fehler beim Parsen des Wertes '%s' von gc.logexpiry"
+msgstr "Fehler beim Parsen des \"prune expiry\" Wertes %s"
 
 #: builtin/gc.c:559
 #, c-format
 msgid "Auto packing the repository in background for optimum performance.\n"
 msgstr ""
 "Die Datenbank des Repositories wird für eine optimale Performance im\n"
 "Hintergrund komprimiert.\n"
 
 #: builtin/gc.c:561
 #, c-format
 msgid "Auto packing the repository for optimum performance.\n"
@@ -10080,25 +10106,24 @@ msgstr "Kann existierende Informationen zu Objekt %s nicht lesen."
 #: builtin/index-pack.c:825
 #, c-format
 msgid "cannot read existing object %s"
 msgstr "Kann existierendes Objekt %s nicht lesen."
 
 #: builtin/index-pack.c:839
 #, c-format
 msgid "invalid blob object %s"
 msgstr "ungültiges Blob-Objekt %s"
 
 #: builtin/index-pack.c:842 builtin/index-pack.c:860
-#, fuzzy
 msgid "fsck error in packed object"
-msgstr "gepackte Objekte ignorieren"
+msgstr "fsck Fehler in gepacktem Objekt"
 
 #: builtin/index-pack.c:857
 #, c-format
 msgid "invalid %s"
 msgstr "Ungültiger Objekt-Typ %s"
 
 #: builtin/index-pack.c:862
 #, c-format
 msgid "Not all child objects of %s are reachable"
 msgstr "Nicht alle Kind-Objekte von %s sind erreichbar"
 
@@ -10243,25 +10268,24 @@ msgid "--fix-thin cannot be used without --stdin"
 msgstr "Die Option --fix-thin kann nicht ohne --stdin verwendet werden."
 
 #: builtin/index-pack.c:1776
 msgid "--stdin requires a git repository"
 msgstr "--stdin erfordert ein Git-Repository"
 
 #: builtin/index-pack.c:1782
 msgid "--verify with no packfile name given"
 msgstr "Die Option --verify wurde ohne Namen der Paketdatei angegeben."
 
 #: builtin/index-pack.c:1832 builtin/unpack-objects.c:578
-#, fuzzy
 msgid "fsck error in pack objects"
-msgstr "Fehler in Objekt: %s"
+msgstr "fsck Fehler beim Packen von Objekten"
 
 #: builtin/init-db.c:55
 #, c-format
 msgid "cannot stat '%s'"
 msgstr "Kann '%s' nicht lesen"
 
 #: builtin/init-db.c:61
 #, c-format
 msgid "cannot stat template '%s'"
 msgstr "kann Vorlage '%s' nicht lesen"
 
@@ -12098,30 +12122,30 @@ msgstr "Schreibe Objekte"
 msgid "disabling bitmap writing, as some objects are not being packed"
 msgstr ""
 "Deaktiviere Schreiben der Bitmap, da einige Objekte nicht in eine Pack-"
 "Datei\n"
 "geschrieben wurden."
 
 #: builtin/pack-objects.c:1765
 msgid "Counting objects"
 msgstr "Zähle Objekte"
 
 #: builtin/pack-objects.c:1895
-#, fuzzy, c-format
+#, c-format
 msgid "unable to get size of %s"
-msgstr "Konnte %s nicht nach %s verschieben"
+msgstr "Konnte Größe von %s nicht bestimmen."
 
 #: builtin/pack-objects.c:1910
-#, fuzzy, c-format
+#, c-format
 msgid "unable to parse object header of %s"
-msgstr "Konnte Objekt '%s' nicht parsen."
+msgstr "Konnte Kopfbereich von Objekt '%s' nicht parsen."
 
 #: builtin/pack-objects.c:2564
 msgid "Compressing objects"
 msgstr "Komprimiere Objekte"
 
 #: builtin/pack-objects.c:2735
 msgid "invalid value for --missing"
 msgstr "Ungültiger Wert für --missing."
 
 #: builtin/pack-objects.c:3067
 #, c-format
@@ -12253,25 +12277,24 @@ msgstr "dünnere Pakete erzeugen"
 
 #: builtin/pack-objects.c:3163
 msgid "create packs suitable for shallow fetches"
 msgstr ""
 "Pakete geeignet für Abholung mit unvollständiger Historie (shallow) erzeugen"
 
 #: builtin/pack-objects.c:3165
 msgid "ignore packs that have companion .keep file"
 msgstr "Pakete ignorieren, die .keep Dateien haben"
 
 #: builtin/pack-objects.c:3167
-#, fuzzy
 msgid "ignore this pack"
-msgstr "kleinere Pakete verwenden"
+msgstr "dieses Paket ignorieren"
 
 #: builtin/pack-objects.c:3169
 msgid "pack compression level"
 msgstr "Komprimierungsgrad für Paketierung"
 
 #: builtin/pack-objects.c:3171
 msgid "do not hide commits by grafts"
 msgstr "keine künstlichen Vorgänger-Commits (\"grafts\") verbergen"
 
 #: builtin/pack-objects.c:3173
 msgid "use a bitmap index if available to speed up counting objects"
@@ -12287,33 +12310,32 @@ msgid "handling for missing objects"
 msgstr "Behandlung für fehlende Objekte"
 
 #: builtin/pack-objects.c:3181
 msgid "do not pack objects in promisor packfiles"
 msgstr ""
 "keine Objekte aus Packdateien von partiell geklonten Remote-Repositories "
 "packen"
 
 #: builtin/pack-objects.c:3205
 #, c-format
 msgid "delta chain depth %d is too deep, forcing %d"
-msgstr ""
+msgstr "Tiefe für Verkettung von Unterschieden %d ist zu tief, erzwinge %d"
 
 #: builtin/pack-objects.c:3210
 #, c-format
 msgid "pack.deltaCacheLimit is too high, forcing %d"
-msgstr ""
+msgstr "pack.deltaCacheLimit ist zu hoch, erzwinge %d"
 
 #: builtin/pack-objects.c:3338
-#, fuzzy
 msgid "Enumerating objects"
-msgstr "Schreibe Objekte"
+msgstr "Objekte aufzählen"
 
 #: builtin/pack-refs.c:7
 msgid "git pack-refs [<options>]"
 msgstr "git pack-refs [<Optionen>]"
 
 #: builtin/pack-refs.c:15
 msgid "pack everything"
 msgstr "alles packen"
 
 #: builtin/pack-refs.c:16
 msgid "prune loose refs (default)"
@@ -12920,29 +12942,28 @@ msgid "git rebase--helper [<options>]"
 msgstr "git rebase--helper [<Optionen>]"
 
 #: builtin/rebase--helper.c:24
 msgid "keep empty commits"
 msgstr "leere Commits behalten"
 
 #: builtin/rebase--helper.c:26 builtin/revert.c:123
 msgid "allow commits with empty messages"
 msgstr "Commits mit leerer Beschreibung erlauben"
 
 #: builtin/rebase--helper.c:27
-#, fuzzy
 msgid "rebase merge commits"
-msgstr "ungültiger Merge-Tag in Commit '%s'"
+msgstr "Rebase auf Merge-Commits ausführen"
 
 #: builtin/rebase--helper.c:29
 msgid "keep original branch points of cousins"
-msgstr ""
+msgstr "originale Branch-Punkte der Cousins behalten"
 
 #: builtin/rebase--helper.c:30
 msgid "continue rebase"
 msgstr "Rebase fortsetzen"
 
 #: builtin/rebase--helper.c:32
 msgid "abort rebase"
 msgstr "Rebase abbrechen"
 
 #: builtin/rebase--helper.c:35
 msgid "make rebase script"
@@ -12966,23 +12987,23 @@ msgstr "nicht erforderliche \"pick\"-Befehle auslassen"
 
 #: builtin/rebase--helper.c:45
 msgid "rearrange fixup/squash lines"
 msgstr "fixup/squash-Zeilen umordnen"
 
 #: builtin/rebase--helper.c:47
 msgid "insert exec commands in todo list"
 msgstr "\"exec\"-Befehle in TODO-Liste einfügen"
 
 #: builtin/rebase--helper.c:68
 msgid "--[no-]rebase-cousins has no effect without --rebase-merges"
-msgstr ""
+msgstr "--[no-]rebase-cousins hat ohne --rebase-merges keine Auswirkung"
 
 #: builtin/receive-pack.c:31
 msgid "git receive-pack <git-dir>"
 msgstr "git receive-pack <Git-Verzeichnis>"
 
 #: builtin/receive-pack.c:842
 msgid ""
 "By default, updating the current branch in a non-bare repository\n"
 "is denied, because it will make the index and work tree inconsistent\n"
 "with what you pushed, and will require 'git reset --hard' to match\n"
 "the work tree to HEAD.\n"
@@ -13288,25 +13309,25 @@ msgstr " ???"
 #: builtin/remote.c:962
 #, c-format
 msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
 msgstr "ungültiges branch.%s.merge; kann Rebase nicht auf > 1 Branch ausführen"
 
 #: builtin/remote.c:971
 #, c-format
 msgid "rebases interactively onto remote %s"
 msgstr "interaktiver Rebase auf Remote-Branch %s"
 
 #: builtin/remote.c:973
-#, fuzzy, c-format
+#, c-format
 msgid "rebases interactively (with merges) onto remote %s"
-msgstr "interaktiver Rebase auf Remote-Branch %s"
+msgstr "interaktiver Rebase (mit Merges) auf Remote-Branch %s"
 
 #: builtin/remote.c:976
 #, c-format
 msgid "rebases onto remote %s"
 msgstr "Rebase auf Remote-Branch %s"
 
 #: builtin/remote.c:980
 #, c-format
 msgid " merges with remote %s"
 msgstr " führt mit Remote-Branch %s zusammen"
 
@@ -13650,27 +13671,24 @@ msgstr "maximale Anzahl von Threads limitieren"
 
 #: builtin/repack.c:210
 msgid "maximum size of each packfile"
 msgstr "maximale Größe für jede Paketdatei"
 
 #: builtin/repack.c:212
 msgid "repack objects in packs marked with .keep"
 msgstr ""
 "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
 
 #: builtin/repack.c:214
-#, fuzzy
 msgid "do not repack this pack"
-msgstr ""
-"keine Objekte aus Packdateien von partiell geklonten Remote-Repositories "
-"packen"
+msgstr "dieses Paket nicht neu packen"
 
 #: builtin/repack.c:224
 msgid "cannot delete packs in a precious-objects repo"
 msgstr "kann Pack-Dateien in precious-objects Repository nicht löschen"
 
 #: builtin/repack.c:228
 msgid "--keep-unreachable and -A are incompatible"
 msgstr "--keep-unreachable und -A sind inkompatibel"
 
 #: builtin/repack.c:425 builtin/worktree.c:139
 #, c-format
@@ -13682,25 +13700,24 @@ msgid "git replace [-f] <object> <replacement>"
 msgstr "git replace [-f] <Objekt> <Ersetzung>"
 
 #: builtin/replace.c:23
 msgid "git replace [-f] --edit <object>"
 msgstr "git replace [-f] --edit <Objekt>"
 
 #: builtin/replace.c:24
 msgid "git replace [-f] --graft <commit> [<parent>...]"
 msgstr "git replace [-f] --graft <Commit> [<Eltern-Commit>...]"
 
 #: builtin/replace.c:25
-#, fuzzy
 msgid "git replace [-f] --convert-graft-file"
-msgstr "git replace [-f] --edit <Objekt>"
+msgstr "git replace [-f] --convert-graft-file"
 
 #: builtin/replace.c:26
 msgid "git replace -d <object>..."
 msgstr "git replace -d <Objekt>..."
 
 #: builtin/replace.c:27
 msgid "git replace [--format=<format>] [-l [<pattern>]]"
 msgstr "git replace [--format=<Format>] [-l [<Muster>]]"
 
 #: builtin/replace.c:371 builtin/replace.c:415 builtin/replace.c:445
 #, c-format
@@ -13733,48 +13750,49 @@ msgstr "Der ursprüngliche Commit '%s' hat eine GPG-Signatur."
 
 #: builtin/replace.c:461
 msgid "the signature will be removed in the replacement commit!"
 msgstr "Die Signatur wird in dem Ersetzungs-Commit entfernt!"
 
 #: builtin/replace.c:471
 #, c-format
 msgid "could not write replacement commit for: '%s'"
 msgstr "Konnte Ersetzungs-Commit für '%s' nicht schreiben"
 
 #: builtin/replace.c:514
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "could not convert the following graft(s):\n"
 "%s"
-msgstr "Würde das folgende Element entfernen:"
+msgstr ""
+"Konnte die folgenden künstlichen Vorgänger (\"grafts\") nicht konvertieren:\n"
+"%s"
 
 #: builtin/replace.c:535
 msgid "list replace refs"
 msgstr "ersetzende Referenzen auflisten"
 
 #: builtin/replace.c:536
 msgid "delete replace refs"
 msgstr "ersetzende Referenzen löschen"
 
 #: builtin/replace.c:537
 msgid "edit existing object"
 msgstr "existierendes Objekt bearbeiten"
 
 #: builtin/replace.c:538
 msgid "change a commit's parents"
 msgstr "Eltern-Commits eines Commits ändern"
 
 #: builtin/replace.c:539
-#, fuzzy
 msgid "convert existing graft file"
-msgstr "das Überschreiben bereits existierender Dateien erzwingen"
+msgstr "existierende Datei des künstlichen Vorgängers (\"graft\") konvertieren"
 
 #: builtin/replace.c:540
 msgid "replace the ref if it exists"
 msgstr "die Referenz ersetzen, wenn sie existiert"
 
 #: builtin/replace.c:542
 msgid "do not pretty-print contents for --edit"
 msgstr "keine ansprechende Anzeige des Objektinhaltes für --edit"
 
 #: builtin/replace.c:543
 msgid "use this format"
@@ -14157,44 +14175,40 @@ msgid "use stateless RPC protocol"
 msgstr "zustandsloses RPC-Protokoll verwenden"
 
 #: builtin/send-pack.c:178
 msgid "read refs from stdin"
 msgstr "Referenzen von der Standard-Eingabe lesen"
 
 #: builtin/send-pack.c:179
 msgid "print status from remote helper"
 msgstr "Status des Remote-Helpers ausgeben"
 
 #: builtin/serve.c:7
-#, fuzzy
 msgid "git serve [<options>]"
-msgstr "git repack [<Optionen>]"
+msgstr "git serve [<Optionen>]"
 
 #: builtin/serve.c:17 builtin/upload-pack.c:23
 msgid "quit after a single request/response exchange"
 msgstr "nach einem einzigen Request/Response-Austausch beenden"
 
 #: builtin/serve.c:19
-#, fuzzy
 msgid "exit immediately after advertising capabilities"
-msgstr "direkt nach der initialen Angabe der Commits beenden"
+msgstr "direkt nach Anzeige der angebotenen Fähigkeiten beenden"
 
 #: builtin/shortlog.c:14
-#, fuzzy
 msgid "git shortlog [<options>] [<revision-range>] [[--] <path>...]"
-msgstr "git shortlog [<Optionen>] [<Commitbereich>] [[--] [<Pfad>...]]"
+msgstr "git shortlog [<Optionen>] [<Commitbereich>] [[--] <Pfad>...]"
 
 #: builtin/shortlog.c:15
-#, fuzzy
 msgid "git log --pretty=short | git shortlog [<options>]"
-msgstr "git worktree list [<Optionen>]"
+msgstr "git log --pretty=short | git shortlog [<Optionen>]"
 
 #: builtin/shortlog.c:264
 msgid "Group by committer rather than author"
 msgstr "über Commit-Ersteller anstatt Autor gruppieren"
 
 #: builtin/shortlog.c:266
 msgid "sort output according to the number of commits per author"
 msgstr "die Ausgabe entsprechend der Anzahl von Commits pro Autor sortieren"
 
 #: builtin/shortlog.c:268
 msgid "Suppress commit descriptions, only provides commit count"
@@ -14205,27 +14219,24 @@ msgid "Show the email address of each author"
 msgstr "die E-Mail-Adresse von jedem Autor anzeigen"
 
 #: builtin/shortlog.c:271
 msgid "w[,i1[,i2]]"
 msgstr "w[,i1[,i2]]"
 
 #: builtin/shortlog.c:272
 msgid "Linewrap output"
 msgstr "Ausgabe mit Zeilenumbrüchen"
 
 #: builtin/shortlog.c:298
-#, fuzzy
 msgid "too many arguments given outside repository"
-msgstr ""
-"zu viele Argumente angegeben, um Konfiguration zu Upstream-Branch zu "
-"entfernen"
+msgstr "zu viele Argumente außerhalb des Repositories angegeben"
 
 #: builtin/show-branch.c:12
 msgid ""
 "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
 "\t\t[--current] [--color[=<when>] | --no-color] [--sparse]\n"
 "\t\t[--more=<n> | --list | --independent | --merge-base]\n"
 "\t\t[--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"
 msgstr ""
 "git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
 "\t\t[--current] [--color[=<Wann>] | --no-color] [--sparse]\n"
 "\t\t[--more=<n> | --list | --independent | --merge-base]\n"
@@ -15457,40 +15468,40 @@ msgstr "Arbeitsverzeichnisse älter als <Zeit> verfallen lassen"
 #: builtin/worktree.c:229
 #, c-format
 msgid "'%s' already exists"
 msgstr "'%s' existiert bereits"
 
 #: builtin/worktree.c:260
 #, c-format
 msgid "could not create directory of '%s'"
 msgstr "Konnte Verzeichnis '%s' nicht erstellen."
 
 #: builtin/worktree.c:373 builtin/worktree.c:379
-#, fuzzy, c-format
+#, c-format
 msgid "Preparing worktree (new branch '%s')"
-msgstr "Fehler beim Entfernen des Branches '%s'"
+msgstr "Bereite Arbeitsverzeichnis vor (neuer Branch '%s')"
 
 #: builtin/worktree.c:375
 #, c-format
 msgid "Preparing worktree (resetting branch '%s'; was at %s)"
-msgstr ""
+msgstr "Bereite Arbeitsverzeichnis vor (setze Branch '%s' um; war bei %s)"
 
 #: builtin/worktree.c:384
 #, c-format
 msgid "Preparing worktree (checking out '%s')"
-msgstr ""
+msgstr "Bereite Arbeitsverzeichnis vor (checke '%s' aus)"
 
 #: builtin/worktree.c:390
-#, fuzzy, c-format
+#, c-format
 msgid "Preparing worktree (detached HEAD %s)"
-msgstr "Bereite %s vor (Identifikation %s)"
+msgstr "Bereite Arbeitsverzeichnis vor (losgelöster HEAD %s)"
 
 #: builtin/worktree.c:431
 msgid "checkout <branch> even if already checked out in other worktree"
 msgstr ""
 "<Branch> auschecken, auch wenn dieser bereits in einem anderen "
 "Arbeitsverzeichnis ausgecheckt ist"
 
 #: builtin/worktree.c:434
 msgid "create a new branch"
 msgstr "neuen Branch erstellen"
 
@@ -15661,34 +15672,33 @@ msgstr ""
 "Ziehen Sie in Betracht\n"
 "\n"
 "\tchmod 0700 %s\n"
 "\n"
 "auszuführen."
 
 #: credential-cache--daemon.c:271
 msgid "print debugging messages to stderr"
 msgstr "Meldungen zur Fehlersuche in Standard-Fehlerausgabe ausgeben"
 
 #: git.c:26
-#, fuzzy
 msgid ""
 "git [--version] [--help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
 "bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
 "           <command> [<args>]"
 msgstr ""
 "git [--version] [--help] [-C <Pfad>] [-c <Name>=<Wert>]\n"
 "           [--exec-path[=<Pfad>]] [--html-path] [--man-path] [--info-path]\n"
-"           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
+"           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
 "           [--git-dir=<Pfad>] [--work-tree=<Pfad>] [--namespace=<Name>]\n"
 "           <Befehl> [<Argumente>]"
 
 #: git.c:33
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
 "concept guides. See 'git help <command>' or 'git help <concept>'\n"
 "to read about a specific subcommand or concept."
 msgstr ""
 "'git help -a' und 'git help -g' listet verfügbare Unterbefehle und\n"
 "einige Anleitungen zu Git-Konzepten auf. Benutzen Sie 'git help <Befehl>'\n"
@@ -16223,23 +16233,23 @@ msgstr ""
 "Es sieht so aus, als ob es das Verzeichnis $state_dir_base bereits gibt\n"
 "und es könnte ein anderer Rebase im Gange sein. Wenn das der Fall ist,\n"
 "probieren Sie bitte\n"
 "\t$cmd_live_rebase\n"
 "Wenn das nicht der Fall ist, probieren Sie bitte\n"
 "\t$cmd_clear_stale_rebase\n"
 "und führen Sie diesen Befehl nochmal aus. Es wird angehalten, falls noch\n"
 "etwas Schützenswertes vorhanden ist."
 
 #: git-rebase.sh:509
 msgid "error: cannot combine '--signoff' with '--preserve-merges'"
-msgstr ""
+msgstr "Fehler: '--signoff' und '--preserve-merges' können nicht kombiniert werden."
 
 #: git-rebase.sh:537
 #, sh-format
 msgid "invalid upstream '$upstream_name'"
 msgstr "Ungültiger Upstream-Branch '$upstream_name'."
 
 #: git-rebase.sh:561
 #, sh-format
 msgid "$onto_name: there are more than one merge bases"
 msgstr "$onto_name: es gibt mehr als eine Merge-Basis"
 
@@ -16664,51 +16674,57 @@ msgstr ""
 #: git-parse-remote.sh:89
 #, sh-format
 msgid "See git-${cmd}(1) for details."
 msgstr "Siehe git-${cmd}(1) für weitere Details."
 
 #: git-rebase--interactive.sh:142
 #, sh-format
 msgid "Rebasing ($new_count/$total)"
 msgstr "Führe Rebase aus ($new_count/$total)"
 
 #: git-rebase--interactive.sh:158
-#, fuzzy
 msgid ""
 "\n"
 "Commands:\n"
 "p, pick <commit> = use commit\n"
 "r, reword <commit> = use commit, but edit the commit message\n"
 "e, edit <commit> = use commit, but stop for amending\n"
 "s, squash <commit> = use commit, but meld into previous commit\n"
 "f, fixup <commit> = like \"squash\", but discard this commit's log message\n"
 "x, exec <commit> = run command (the rest of the line) using shell\n"
 "d, drop <commit> = remove commit\n"
 "l, label <label> = label current HEAD with a name\n"
 "t, reset <label> = reset HEAD to a label\n"
 "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n"
 ".       create a merge commit using the original merge commit's\n"
 ".       message (or the oneline, if no original merge commit was\n"
 ".       specified). Use -c <commit> to reword the commit message.\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
 "\n"
 "Befehle:\n"
-"p, pick = Commit verwenden\n"
-"r, reword = Commit verwenden, aber Commit-Beschreibung bearbeiten\n"
-"e, edit = Commit verwenden, aber zum Nachbessern anhalten\n"
-"s, squash = Commit verwenden, aber mit vorherigem Commit vereinen\n"
-"f, fixup = wie \"squash\", aber diese Commit-Beschreibung verwerfen\n"
-"x, exec = Befehl (Rest der Zeile) mittels Shell ausführen\n"
-"d, drop = Commit entfernen\n"
+"p, pick <Commit> = Commit verwenden\n"
+"r, reword <Commit> = Commit verwenden, aber Commit-Beschreibung bearbeiten\n"
+"e, edit <Commit> = Commit verwenden, aber zum Nachbessern anhalten\n"
+"s, squash <Commit> = Commit verwenden, aber mit vorherigem Commit vereinen\n"
+"f, fixup <Commit> = wie \"squash\", aber diese Commit-Beschreibung verwerfen\n"
+"x, exec <Commit> = Befehl (Rest der Zeile) mittels Shell ausführen\n"
+"d, drop <Commit> = Commit entfernen\n"
+"l, label <Label> = aktuellen HEAD mit Label versehen\n"
+"t, reset <Label> = HEAD zu einem Label umsetzen\n"
+"m, merge [-C <Commit> | -c <Commit>] <Label> [# <eineZeile>]\n"
+".       Merge-Commit mit der originalen Merge-Commit-Beschreibung erstellen\n"
+".       (oder die eine Zeile, wenn keine originale Merge-Commit-Beschreibung\n"
+".       spezifiziert ist). Benutzen Sie -c <Commit> zum Bearbeiten der\n"
+".       Commit-Beschreibung.\n"
 "\n"
 "Diese Zeilen können umsortiert werden; Sie werden von oben nach unten\n"
 "ausgeführt.\n"
 
 #: git-rebase--interactive.sh:179
 msgid ""
 "\n"
 "Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
 msgstr ""
 "\n"
 "Keine Zeile entfernen. Benutzen Sie 'drop', um explizit einen Commit zu\n"
@@ -16997,32 +17013,32 @@ msgstr "Konnte temporäres Verzeichnis $state_dir nicht erstellen."
 msgid "Could not mark as interactive"
 msgstr "Konnte nicht als interaktiven Rebase markieren."
 
 #: git-rebase--interactive.sh:915
 #, sh-format
 msgid "Rebase $shortrevisions onto $shortonto ($todocount command)"
 msgid_plural "Rebase $shortrevisions onto $shortonto ($todocount commands)"
 msgstr[0] "Rebase von $shortrevisions auf $shortonto ($todocount Kommando)"
 msgstr[1] "Rebase von $shortrevisions auf $shortonto ($todocount Kommandos)"
 
 #: git-rebase--interactive.sh:920
-#, fuzzy
 msgid ""
 "\n"
 "\tHowever, if you remove everything, the rebase will be aborted.\n"
 "\n"
 "\t"
 msgstr ""
 "\n"
-"Wenn Sie jedoch alles löschen, wird der Rebase abgebrochen.\n"
+"\tWenn Sie jedoch alles löschen, wird der Rebase abgebrochen.\n"
 "\n"
+"\t"
 
 #: git-rebase--interactive.sh:927
 msgid "Note that empty commits are commented out"
 msgstr "Leere Commits sind auskommentiert."
 
 #: git-rebase--interactive.sh:980
 msgid "Could not generate todo list"
 msgstr "Konnte TODO-Liste nicht erzeugen."
 
 #: git-rebase--interactive.sh:1001 git-rebase--interactive.sh:1006
 msgid "Could not init rewritten commits"
@@ -17899,25 +17915,24 @@ msgstr ""
 "\n"
 "    Für weitere Informationen, führen Sie 'git send-email --help' aus.\n"
 "    Um das aktuelle Verhalten beizubehalten, aber diese Meldung zu "
 "unterdrücken,\n"
 "    führen Sie 'git config --global sendemail.confirm auto' aus.\n"
 "\n"
 
 #. TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
 #. translation. The program will only accept English input
 #. at this point.
 #: git-send-email.perl:1415
-#, fuzzy
 msgid "Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "
-msgstr "Diese E-Mail versenden? (Ja [y]|Nein [n]|Beenden [q]|Alle [a]): "
+msgstr "Diese E-Mail versenden? (Ja [y]|Nein [n]|Bearbeiten [e]|Beenden [q]|Alle [a]): "
 
 #: git-send-email.perl:1418
 msgid "Send this email reply required"
 msgstr "Zum Versenden dieser E-Mail ist eine Antwort erforderlich."
 
 #: git-send-email.perl:1446
 msgid "The required SMTP server is not properly defined."
 msgstr "Der erforderliche SMTP-Server ist nicht korrekt definiert."
 
 #: git-send-email.perl:1493
 #, perl-format
-- 
2.18.0.203.gfac676dfb9


^ permalink raw reply related	[relevance 1%]

* Re: is there a reason pre-commit.sample uses "git diff-index"?
  @ 2018-05-31 23:25  4%         ` Stefan Beller
  0 siblings, 0 replies; 200+ results
From: Stefan Beller @ 2018-05-31 23:25 UTC (permalink / raw)
  To: Robert P. J. Day; +Cc: Johannes Sixt, Duy Nguyen, Git Mailing list

On Thu, May 31, 2018 at 4:09 PM, Robert P. J. Day <rpjday@crashcourse.ca> wrote:
> On Fri, 1 Jun 2018, Johannes Sixt wrote:
>
>> Am 31.05.2018 um 19:27 schrieb Robert P. J. Day:
>> > On Thu, 31 May 2018, Duy Nguyen wrote:
>> >> git diff-index is "plumbing", designed for writing scripts. "git
>> >> diff" on the other hand is for users and its behavior may change
>> >> even if it breaks backward compatibility.
>> >
>> >    ah, this was a philosophical underpinning i was unaware of. i
>> > see occasional explanations of git porcelain versus plumbing, but
>> > i don't recall anyone simply stating that the plumbing is meant to
>> > have a long-term stability that is not guaranteed for the
>> > porcelain.
>>
>> So, there you have it. ;) Plumbing commands offer long-term
>> stability. That is not just philosophical, but practically relevant.
>>
>> >    in any event, this does mean that, stability issues aside, "git
>> > diff" would apparently have worked just fine for that hook.
>>
>> It may have worked just fine. You should still not use it.
>>
>> Didn't you say that you are teaching git and hooks? Then you should
>> teach the right thing, and the right thing is to use plumbing for
>> scripts.
>
>   sure, i agree, but i don't recall *ever* running across the claim
> that the "plumbing" commands had a long-term stability and backward
> compatibility that the porcelain commands did not. is that mentioned
> anywhere?

`man git`

LOW-LEVEL COMMANDS (PLUMBING)
       Although Git includes its own porcelain layer, its low-level commands
       are sufficient to support development of alternative porcelains.
       Developers of such porcelains might start by reading about git-update-
       index(1) and git-read-tree(1).

       The interface (input, output, set of options and the semantics) to
       these low-level commands are meant to be a lot more stable than
       Porcelain level commands, because these commands are primarily for
       scripted use. The interface to Porcelain commands on the other hand are
       subject to change in order to improve the end user experience.

One example that Junio seemed to worry about was 940a911f8ec (log:
if --decorate is not given, default to --decorate=auto, 2017-03-23), as git log
seems to be used pseudo-plumbing-ly as there is no good and equally powerful
plumbing command, so the likelihood of git-log calls in scripts out
there is high.

So maybe the community should strive to be more aggressive about
changing the porcelain interface for the better.

One thing that we discussed internally for example is changing the
output of the porcelain output of fetch, pull and push to give less
cryptic output, but rather a one line progress bar (and only show errors
when they occur). I think that would be an improvement, as I don't think
many people care about the exact numbers of objects transferred in
a push/fetch, but rather want to have an estimate of the time left for
example. Also a one line progress bar might save some precious screen
real estate.

Stefan

^ permalink raw reply	[relevance 4%]

* [PATCH 3/5] t6036, t6042: prefer test_path_is_file, test_path_is_missing
    2018-05-24  7:04  3% ` [PATCH 1/5] t6036, t6042: use test_create_repo to keep tests independent Elijah Newren
@ 2018-05-24  7:04  5% ` Elijah Newren
  1 sibling, 0 replies; 200+ results
From: Elijah Newren @ 2018-05-24  7:04 UTC (permalink / raw)
  To: git; +Cc: gitster, Elijah Newren

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 t/t6036-recursive-corner-cases.sh    |  4 +--
 t/t6042-merge-rename-corner-cases.sh | 40 ++++++++++++++--------------
 2 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index 3e659cff28..b716155723 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -488,7 +488,7 @@ test_expect_success 'merge of D & E2 fails but has appropriate contents' '
 		test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
 		test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
 
-		test -f a~HEAD
+		test_path_is_file a~HEAD
 	)
 '
 
@@ -512,7 +512,7 @@ test_expect_success 'merge of E2 & D fails but has appropriate contents' '
 		test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
 		test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
 
-		test -f a~D^0
+		test_path_is_file a~D^0
 	)
 '
 
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index b76da8fcdf..90225b8bcd 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -38,7 +38,7 @@ test_expect_success "Does git preserve Gollum's precious artifact?" '
 		test_must_fail git merge -s recursive rename-the-ring &&
 
 		# Make sure git did not delete an untracked file
-		test -f ring
+		test_path_is_file ring
 	)
 '
 
@@ -213,8 +213,8 @@ test_expect_failure 'detect rename/add-source and preserve all data' '
 		git ls-files -o >out &&
 		test_line_count = 1 out &&
 
-		test -f a &&
-		test -f b &&
+		test_path_is_file a &&
+		test_path_is_file b &&
 
 		test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
 		test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
@@ -236,8 +236,8 @@ test_expect_failure 'detect rename/add-source and preserve all data, merge other
 		git ls-files -o >out &&
 		test_line_count = 1 out &&
 
-		test -f a &&
-		test -f b &&
+		test_path_is_file a &&
+		test_path_is_file b &&
 
 		test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
 		test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
@@ -302,8 +302,8 @@ test_expect_success 'rename/directory conflict + clean content merge' '
 
 		test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
 
-		test -f newfile/realfile &&
-		test -f newfile~HEAD
+		test_path_is_file newfile/realfile &&
+		test_path_is_file newfile~HEAD
 	)
 '
 
@@ -340,8 +340,8 @@ test_expect_success 'rename/directory conflict + content merge conflict' '
 		test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
 		test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
 
-		test -f newfile/realfile &&
-		test -f newfile~HEAD
+		test_path_is_file newfile/realfile &&
+		test_path_is_file newfile~HEAD
 	)
 '
 
@@ -394,7 +394,7 @@ test_expect_success 'disappearing dir in rename/directory conflict handled' '
 		echo 7 >>expect &&
 		test_cmp expect sub &&
 
-		test -f sub
+		test_path_is_file sub
 	)
 '
 
@@ -453,10 +453,10 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 		git ls-files -o >out &&
 		test_line_count = 3 out &&
 
-		test ! -f a &&
-		test ! -f b &&
-		test -f c~HEAD &&
-		test -f c~C^0 &&
+		test_path_is_missing a &&
+		test_path_is_missing b &&
+		test_path_is_file c~HEAD &&
+		test_path_is_file c~C^0 &&
 
 		test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
 		test $(git hash-object c~C^0) = $(git rev-parse B:b)
@@ -509,7 +509,7 @@ test_expect_success 'merge has correct working tree contents' '
 		test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
 		test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
 
-		test ! -f a &&
+		test_path_is_missing a &&
 		test $(git hash-object b) = $(git rev-parse A:a) &&
 		test $(git hash-object c) = $(git rev-parse A:a)
 	)
@@ -562,9 +562,9 @@ test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge'
 		test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
 		test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
 
-		test -f a &&
-		test -f b &&
-		test -f c
+		test_path_is_file a &&
+		test_path_is_file b &&
+		test_path_is_file c
 	)
 '
 
@@ -664,8 +664,8 @@ test_expect_success 'rename/rename/add-dest merge still knows about conflicting
 		test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
 		test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
 
-		test ! -f b &&
-		test ! -f c
+		test_path_is_missing b &&
+		test_path_is_missing c
 	)
 '
 
-- 
2.17.0.1.gda85003413


^ permalink raw reply related	[relevance 5%]

* [PATCH 1/5] t6036, t6042: use test_create_repo to keep tests independent
  @ 2018-05-24  7:04  3% ` Elijah Newren
  2018-05-24  7:04  5% ` [PATCH 3/5] t6036, t6042: prefer test_path_is_file, test_path_is_missing Elijah Newren
  1 sibling, 0 replies; 200+ results
From: Elijah Newren @ 2018-05-24  7:04 UTC (permalink / raw)
  To: git; +Cc: gitster, Elijah Newren

These tests used pretty strong measures to get a clean slate:
        git rm -rf . &&
        git clean -fdqx &&
        rm -rf .git &&
        git init &&
It's easier, safer (what if a previous test has a bug and accidentally
changes into a directory outside the test path?), and allows re-inspecting
test setup later if we instead just use test_create_repo to put different
tests into separate sub-repositories.

Signed-off-by: Elijah Newren <newren@gmail.com>
---
Best viewed with `git diff -w`...

 t/t6036-recursive-corner-cases.sh    | 854 ++++++++++++++------------
 t/t6042-merge-rename-corner-cases.sh | 887 ++++++++++++++-------------
 2 files changed, 926 insertions(+), 815 deletions(-)

diff --git a/t/t6036-recursive-corner-cases.sh b/t/t6036-recursive-corner-cases.sh
index 18aa88b5c0..cfe6a99771 100755
--- a/t/t6036-recursive-corner-cases.sh
+++ b/t/t6036-recursive-corner-cases.sh
@@ -21,51 +21,60 @@ get_clean_checkout () {
 #
 
 test_expect_success 'setup basic criss-cross + rename with no modifications' '
-	ten="0 1 2 3 4 5 6 7 8 9" &&
-	for i in $ten
-	do
-		echo line $i in a sample file
-	done >one &&
-	for i in $ten
-	do
-		echo line $i in another sample file
-	done >two &&
-	git add one two &&
-	test_tick && git commit -m initial &&
-
-	git branch L1 &&
-	git checkout -b R1 &&
-	git mv one three &&
-	test_tick && git commit -m R1 &&
-
-	git checkout L1 &&
-	git mv two three &&
-	test_tick && git commit -m L1 &&
-
-	git checkout L1^0 &&
-	test_tick && git merge -s ours R1 &&
-	git tag L2 &&
-
-	git checkout R1^0 &&
-	test_tick && git merge -s ours L1 &&
-	git tag R2
+	test_create_repo basic-rename &&
+	(
+		cd basic-rename &&
+
+		ten="0 1 2 3 4 5 6 7 8 9" &&
+		for i in $ten
+		do
+			echo line $i in a sample file
+		done >one &&
+		for i in $ten
+		do
+			echo line $i in another sample file
+		done >two &&
+		git add one two &&
+		test_tick && git commit -m initial &&
+
+		git branch L1 &&
+		git checkout -b R1 &&
+		git mv one three &&
+		test_tick && git commit -m R1 &&
+
+		git checkout L1 &&
+		git mv two three &&
+		test_tick && git commit -m L1 &&
+
+		git checkout L1^0 &&
+		test_tick && git merge -s ours R1 &&
+		git tag L2 &&
+
+		git checkout R1^0 &&
+		test_tick && git merge -s ours L1 &&
+		git tag R2
+	)
 '
 
 test_expect_success 'merge simple rename+criss-cross with no modifications' '
-	git reset --hard &&
-	git checkout L2^0 &&
+	(
+		cd basic-rename &&
+
+		git reset --hard &&
+		git checkout L2^0 &&
 
-	test_must_fail git merge -s recursive R2^0 &&
+		test_must_fail git merge -s recursive R2^0 &&
 
-	test 2 = $(git ls-files -s | wc -l) &&
-	test 2 = $(git ls-files -u | wc -l) &&
-	test 2 = $(git ls-files -o | wc -l) &&
+		test 2 = $(git ls-files -s | wc -l) &&
+		test 2 = $(git ls-files -u | wc -l) &&
+		test 2 = $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
-	test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
+		test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
+		test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
 
-	test $(git rev-parse L2:three) = $(git hash-object three~HEAD) &&
-	test $(git rev-parse R2:three) = $(git hash-object three~R2^0)
+		test $(git rev-parse L2:three) = $(git hash-object three~HEAD) &&
+		test $(git rev-parse R2:three) = $(git hash-object three~R2^0)
+	)
 '
 
 #
@@ -81,58 +90,61 @@ test_expect_success 'merge simple rename+criss-cross with no modifications' '
 #
 
 test_expect_success 'setup criss-cross + rename merges with basic modification' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	ten="0 1 2 3 4 5 6 7 8 9" &&
-	for i in $ten
-	do
-		echo line $i in a sample file
-	done >one &&
-	for i in $ten
-	do
-		echo line $i in another sample file
-	done >two &&
-	git add one two &&
-	test_tick && git commit -m initial &&
-
-	git branch L1 &&
-	git checkout -b R1 &&
-	git mv one three &&
-	echo more >>two &&
-	git add two &&
-	test_tick && git commit -m R1 &&
-
-	git checkout L1 &&
-	git mv two three &&
-	test_tick && git commit -m L1 &&
-
-	git checkout L1^0 &&
-	test_tick && git merge -s ours R1 &&
-	git tag L2 &&
-
-	git checkout R1^0 &&
-	test_tick && git merge -s ours L1 &&
-	git tag R2
+	test_create_repo rename-modify &&
+	(
+		cd rename-modify &&
+
+		ten="0 1 2 3 4 5 6 7 8 9" &&
+		for i in $ten
+		do
+			echo line $i in a sample file
+		done >one &&
+		for i in $ten
+		do
+			echo line $i in another sample file
+		done >two &&
+		git add one two &&
+		test_tick && git commit -m initial &&
+
+		git branch L1 &&
+		git checkout -b R1 &&
+		git mv one three &&
+		echo more >>two &&
+		git add two &&
+		test_tick && git commit -m R1 &&
+
+		git checkout L1 &&
+		git mv two three &&
+		test_tick && git commit -m L1 &&
+
+		git checkout L1^0 &&
+		test_tick && git merge -s ours R1 &&
+		git tag L2 &&
+
+		git checkout R1^0 &&
+		test_tick && git merge -s ours L1 &&
+		git tag R2
+	)
 '
 
 test_expect_success 'merge criss-cross + rename merges with basic modification' '
-	git reset --hard &&
-	git checkout L2^0 &&
+	(
+		cd rename-modify &&
+
+		git checkout L2^0 &&
 
-	test_must_fail git merge -s recursive R2^0 &&
+		test_must_fail git merge -s recursive R2^0 &&
 
-	test 2 = $(git ls-files -s | wc -l) &&
-	test 2 = $(git ls-files -u | wc -l) &&
-	test 2 = $(git ls-files -o | wc -l) &&
+		test 2 = $(git ls-files -s | wc -l) &&
+		test 2 = $(git ls-files -u | wc -l) &&
+		test 2 = $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
-	test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
+		test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
+		test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
 
-	test $(git rev-parse L2:three) = $(git hash-object three~HEAD) &&
-	test $(git rev-parse R2:three) = $(git hash-object three~R2^0)
+		test $(git rev-parse L2:three) = $(git hash-object three~HEAD) &&
+		test $(git rev-parse R2:three) = $(git hash-object three~R2^0)
+	)
 '
 
 #
@@ -156,64 +168,67 @@ test_expect_success 'merge criss-cross + rename merges with basic modification'
 #
 
 test_expect_success 'setup differently handled merges of rename/add conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n" >a &&
-	git add a &&
-	test_tick && git commit -m A &&
-
-	git branch B &&
-	git checkout -b C &&
-	echo 10 >>a &&
-	echo "other content" >>new_a &&
-	git add a new_a &&
-	test_tick && git commit -m C &&
-
-	git checkout B &&
-	git mv a new_a &&
-	test_tick && git commit -m B &&
-
-	git checkout B^0 &&
-	test_must_fail git merge C &&
-	git clean -f &&
-	test_tick && git commit -m D &&
-	git tag D &&
-
-	git checkout C^0 &&
-	test_must_fail git merge B &&
-	rm new_a~HEAD new_a &&
-	printf "Incorrectly merged content" >>new_a &&
-	git add -u &&
-	test_tick && git commit -m E &&
-	git tag E
+	test_create_repo rename-add &&
+	(
+		cd rename-add &&
+
+		printf "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n" >a &&
+		git add a &&
+		test_tick && git commit -m A &&
+
+		git branch B &&
+		git checkout -b C &&
+		echo 10 >>a &&
+		echo "other content" >>new_a &&
+		git add a new_a &&
+		test_tick && git commit -m C &&
+
+		git checkout B &&
+		git mv a new_a &&
+		test_tick && git commit -m B &&
+
+		git checkout B^0 &&
+		test_must_fail git merge C &&
+		git clean -f &&
+		test_tick && git commit -m D &&
+		git tag D &&
+
+		git checkout C^0 &&
+		test_must_fail git merge B &&
+		rm new_a~HEAD new_a &&
+		printf "Incorrectly merged content" >>new_a &&
+		git add -u &&
+		test_tick && git commit -m E &&
+		git tag E
+	)
 '
 
 test_expect_success 'git detects differently handled merges conflict' '
-	git reset --hard &&
-	git checkout D^0 &&
-
-	test_must_fail git merge -s recursive E^0 &&
-
-	test 3 = $(git ls-files -s | wc -l) &&
-	test 3 = $(git ls-files -u | wc -l) &&
-	test 0 = $(git ls-files -o | wc -l) &&
-
-	test $(git rev-parse :2:new_a) = $(git rev-parse D:new_a) &&
-	test $(git rev-parse :3:new_a) = $(git rev-parse E:new_a) &&
-
-	git cat-file -p B:new_a >>merged &&
-	git cat-file -p C:new_a >>merge-me &&
-	>empty &&
-	test_must_fail git merge-file \
-		-L "Temporary merge branch 2" \
-		-L "" \
-		-L "Temporary merge branch 1" \
-		merged empty merge-me &&
-	sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
-	test $(git rev-parse :1:new_a) = $(git hash-object merged-internal)
+	(
+		cd rename-add &&
+
+		git checkout D^0 &&
+
+		test_must_fail git merge -s recursive E^0 &&
+
+		test 3 = $(git ls-files -s | wc -l) &&
+		test 3 = $(git ls-files -u | wc -l) &&
+		test 0 = $(git ls-files -o | wc -l) &&
+
+		test $(git rev-parse :2:new_a) = $(git rev-parse D:new_a) &&
+		test $(git rev-parse :3:new_a) = $(git rev-parse E:new_a) &&
+
+		git cat-file -p B:new_a >>merged &&
+		git cat-file -p C:new_a >>merge-me &&
+		>empty &&
+		test_must_fail git merge-file \
+			-L "Temporary merge branch 2" \
+			-L "" \
+			-L "Temporary merge branch 1" \
+			merged empty merge-me &&
+		sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
+		test $(git rev-parse :1:new_a) = $(git hash-object merged-internal)
+	)
 '
 
 #
@@ -236,67 +251,75 @@ test_expect_success 'git detects differently handled merges conflict' '
 # Merging commits D & E should result in modify/delete conflict.
 
 test_expect_success 'setup criss-cross + modify/delete resolved differently' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	echo A >file &&
-	git add file &&
-	test_tick &&
-	git commit -m A &&
-
-	git branch B &&
-	git checkout -b C &&
-	git rm file &&
-	test_tick &&
-	git commit -m C &&
-
-	git checkout B &&
-	echo B >file &&
-	git add file &&
-	test_tick &&
-	git commit -m B &&
-
-	git checkout B^0 &&
-	test_must_fail git merge C &&
-	echo B >file &&
-	git add file &&
-	test_tick &&
-	git commit -m D &&
-	git tag D &&
-
-	git checkout C^0 &&
-	test_must_fail git merge B &&
-	git rm file &&
-	test_tick &&
-	git commit -m E &&
-	git tag E
+	test_create_repo modify-delete &&
+	(
+		cd modify-delete &&
+
+		echo A >file &&
+		git add file &&
+		test_tick &&
+		git commit -m A &&
+
+		git branch B &&
+		git checkout -b C &&
+		git rm file &&
+		test_tick &&
+		git commit -m C &&
+
+		git checkout B &&
+		echo B >file &&
+		git add file &&
+		test_tick &&
+		git commit -m B &&
+
+		git checkout B^0 &&
+		test_must_fail git merge C &&
+		echo B >file &&
+		git add file &&
+		test_tick &&
+		git commit -m D &&
+		git tag D &&
+
+		git checkout C^0 &&
+		test_must_fail git merge B &&
+		git rm file &&
+		test_tick &&
+		git commit -m E &&
+		git tag E
+	)
 '
 
 test_expect_success 'git detects conflict merging criss-cross+modify/delete' '
-	git checkout D^0 &&
+	(
+		cd modify-delete &&
+
+		git checkout D^0 &&
 
-	test_must_fail git merge -s recursive E^0 &&
+		test_must_fail git merge -s recursive E^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 2 -eq $(git ls-files -u | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 2 -eq $(git ls-files -u | wc -l) &&
 
-	test $(git rev-parse :1:file) = $(git rev-parse master:file) &&
-	test $(git rev-parse :2:file) = $(git rev-parse B:file)
+		test $(git rev-parse :1:file) = $(git rev-parse master:file) &&
+		test $(git rev-parse :2:file) = $(git rev-parse B:file)
+	)
 '
 
 test_expect_success 'git detects conflict merging criss-cross+modify/delete, reverse direction' '
-	git reset --hard &&
-	git checkout E^0 &&
+	(
+		cd modify-delete &&
+
+		git reset --hard &&
+		git checkout E^0 &&
 
-	test_must_fail git merge -s recursive D^0 &&
+		test_must_fail git merge -s recursive D^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 2 -eq $(git ls-files -u | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 2 -eq $(git ls-files -u | wc -l) &&
 
-	test $(git rev-parse :1:file) = $(git rev-parse master:file) &&
-	test $(git rev-parse :3:file) = $(git rev-parse B:file)
+		test $(git rev-parse :1:file) = $(git rev-parse master:file) &&
+		test $(git rev-parse :3:file) = $(git rev-parse B:file)
+	)
 '
 
 #
@@ -336,120 +359,136 @@ test_expect_success 'git detects conflict merging criss-cross+modify/delete, rev
 #
 
 test_expect_success 'setup differently handled merges of directory/file conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	>ignore-me &&
-	git add ignore-me &&
-	test_tick &&
-	git commit -m A &&
-	git tag A &&
-
-	git branch B &&
-	git checkout -b C &&
-	mkdir a &&
-	echo 10 >a/file &&
-	git add a/file &&
-	test_tick &&
-	git commit -m C &&
-
-	git checkout B &&
-	echo 5 >a &&
-	git add a &&
-	test_tick &&
-	git commit -m B &&
-
-	git checkout B^0 &&
-	test_must_fail git merge C &&
-	git clean -f &&
-	rm -rf a/ &&
-	echo 5 >a &&
-	git add a &&
-	test_tick &&
-	git commit -m D &&
-	git tag D &&
-
-	git checkout C^0 &&
-	test_must_fail git merge B &&
-	git clean -f &&
-	git rm --cached a &&
-	echo 10 >a/file &&
-	git add a/file &&
-	test_tick &&
-	git commit -m E1 &&
-	git tag E1 &&
-
-	git checkout C^0 &&
-	test_must_fail git merge B &&
-	git clean -f &&
-	git rm --cached a &&
-	printf "10\n11\n" >a/file &&
-	git add a/file &&
-	test_tick &&
-	git commit -m E2 &&
-	git tag E2
+	test_create_repo directory-file &&
+	(
+		cd directory-file &&
+
+		>ignore-me &&
+		git add ignore-me &&
+		test_tick &&
+		git commit -m A &&
+		git tag A &&
+
+		git branch B &&
+		git checkout -b C &&
+		mkdir a &&
+		echo 10 >a/file &&
+		git add a/file &&
+		test_tick &&
+		git commit -m C &&
+
+		git checkout B &&
+		echo 5 >a &&
+		git add a &&
+		test_tick &&
+		git commit -m B &&
+
+		git checkout B^0 &&
+		test_must_fail git merge C &&
+		git clean -f &&
+		rm -rf a/ &&
+		echo 5 >a &&
+		git add a &&
+		test_tick &&
+		git commit -m D &&
+		git tag D &&
+
+		git checkout C^0 &&
+		test_must_fail git merge B &&
+		git clean -f &&
+		git rm --cached a &&
+		echo 10 >a/file &&
+		git add a/file &&
+		test_tick &&
+		git commit -m E1 &&
+		git tag E1 &&
+
+		git checkout C^0 &&
+		test_must_fail git merge B &&
+		git clean -f &&
+		git rm --cached a &&
+		printf "10\n11\n" >a/file &&
+		git add a/file &&
+		test_tick &&
+		git commit -m E2 &&
+		git tag E2
+	)
 '
 
 test_expect_success 'merge of D & E1 fails but has appropriate contents' '
-	get_clean_checkout D^0 &&
+	(
+		cd directory-file &&
 
-	test_must_fail git merge -s recursive E1^0 &&
+		get_clean_checkout D^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 1 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test_must_fail git merge -s recursive E1^0 &&
 
-	test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
-	test $(git rev-parse :2:a) = $(git rev-parse B:a)
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 1 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
+
+		test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+		test $(git rev-parse :2:a) = $(git rev-parse B:a)
+	)
 '
 
 test_expect_success 'merge of E1 & D fails but has appropriate contents' '
-	get_clean_checkout E1^0 &&
+	(
+		cd directory-file &&
+
+		get_clean_checkout E1^0 &&
 
-	test_must_fail git merge -s recursive D^0 &&
+		test_must_fail git merge -s recursive D^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 1 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 1 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
-	test $(git rev-parse :3:a) = $(git rev-parse B:a)
+		test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+		test $(git rev-parse :3:a) = $(git rev-parse B:a)
+	)
 '
 
 test_expect_success 'merge of D & E2 fails but has appropriate contents' '
-	get_clean_checkout D^0 &&
+	(
+		cd directory-file &&
+
+		get_clean_checkout D^0 &&
 
-	test_must_fail git merge -s recursive E2^0 &&
+		test_must_fail git merge -s recursive E2^0 &&
 
-	test 4 -eq $(git ls-files -s | wc -l) &&
-	test 3 -eq $(git ls-files -u | wc -l) &&
-	test 1 -eq $(git ls-files -o | wc -l) &&
+		test 4 -eq $(git ls-files -s | wc -l) &&
+		test 3 -eq $(git ls-files -u | wc -l) &&
+		test 1 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse :2:a) = $(git rev-parse B:a) &&
-	test $(git rev-parse :3:a/file) = $(git rev-parse E2:a/file) &&
-	test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
-	test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+		test $(git rev-parse :2:a) = $(git rev-parse B:a) &&
+		test $(git rev-parse :3:a/file) = $(git rev-parse E2:a/file) &&
+		test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
+		test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
 
-	test -f a~HEAD
+		test -f a~HEAD
+	)
 '
 
 test_expect_success 'merge of E2 & D fails but has appropriate contents' '
-	get_clean_checkout E2^0 &&
+	(
+		cd directory-file &&
 
-	test_must_fail git merge -s recursive D^0 &&
+		get_clean_checkout E2^0 &&
 
-	test 4 -eq $(git ls-files -s | wc -l) &&
-	test 3 -eq $(git ls-files -u | wc -l) &&
-	test 1 -eq $(git ls-files -o | wc -l) &&
+		test_must_fail git merge -s recursive D^0 &&
 
-	test $(git rev-parse :3:a) = $(git rev-parse B:a) &&
-	test $(git rev-parse :2:a/file) = $(git rev-parse E2:a/file) &&
-	test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
-	test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+		test 4 -eq $(git ls-files -s | wc -l) &&
+		test 3 -eq $(git ls-files -u | wc -l) &&
+		test 1 -eq $(git ls-files -o | wc -l) &&
 
-	test -f a~D^0
+		test $(git rev-parse :3:a) = $(git rev-parse B:a) &&
+		test $(git rev-parse :2:a/file) = $(git rev-parse E2:a/file) &&
+		test $(git rev-parse :1:a/file) = $(git rev-parse C:a/file) &&
+		test $(git rev-parse :0:ignore-me) = $(git rev-parse A:ignore-me) &&
+
+		test -f a~D^0
+	)
 '
 
 #
@@ -492,52 +531,55 @@ test_expect_success 'merge of E2 & D fails but has appropriate contents' '
 # but that may cancel out at the final merge stage".
 
 test_expect_success 'setup rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
-	git reset --hard &&
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n6\n" >a &&
-	git add a &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	echo 7 >>b &&
-	git add -u &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a c &&
-	git commit -m C &&
-
-	git checkout -q B^0 &&
-	git merge --no-commit -s ours C^0 &&
-	git mv b newname &&
-	git commit -m "Merge commit C^0 into HEAD" &&
-	git tag D &&
-
-	git checkout -q C^0 &&
-	git merge --no-commit -s ours B^0 &&
-	git mv c newname &&
-	printf "7\n8\n" >>newname &&
-	git add -u &&
-	git commit -m "Merge commit B^0 into HEAD" &&
-	git tag E
+	test_create_repo rename-squared-squared &&
+	(
+		cd rename-squared-squared &&
+
+		printf "1\n2\n3\n4\n5\n6\n" >a &&
+		git add a &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		echo 7 >>b &&
+		git add -u &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a c &&
+		git commit -m C &&
+
+		git checkout -q B^0 &&
+		git merge --no-commit -s ours C^0 &&
+		git mv b newname &&
+		git commit -m "Merge commit C^0 into HEAD" &&
+		git tag D &&
+
+		git checkout -q C^0 &&
+		git merge --no-commit -s ours B^0 &&
+		git mv c newname &&
+		printf "7\n8\n" >>newname &&
+		git add -u &&
+		git commit -m "Merge commit B^0 into HEAD" &&
+		git tag E
+	)
 '
 
 test_expect_success 'handle rename/rename(1to2)/modify followed by what looks like rename/rename(2to1)/modify' '
-	git checkout D^0 &&
+	(
+		cd rename-squared-squared &&
 
-	git merge -s recursive E^0 &&
+		git checkout D^0 &&
 
-	test 1 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		git merge -s recursive E^0 &&
 
-	test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname)
+		test 1 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
+
+		test $(git rev-parse HEAD:newname) = $(git rev-parse E:newname)
+	)
 '
 
 #
@@ -562,59 +604,63 @@ test_expect_success 'handle rename/rename(1to2)/modify followed by what looks li
 # renaming carefully (both in the virtual merge base and later), and getting
 # content merge handled.
 
-test_expect_success 'setup criss-cross + rename/rename/add + modify/modify' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "lots\nof\nwords\nand\ncontent\n" >a &&
-	git add a &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a c &&
-	printf "2\n3\n4\n5\n6\n7\n" >a &&
-	git add a &&
-	git commit -m C &&
-
-	git checkout B^0 &&
-	git merge --no-commit -s ours C^0 &&
-	git checkout C -- a c &&
-	mv a old_a &&
-	echo 1 >a &&
-	cat old_a >>a &&
-	rm old_a &&
-	git add -u &&
-	git commit -m "Merge commit C^0 into HEAD" &&
-	git tag D &&
-
-	git checkout C^0 &&
-	git merge --no-commit -s ours B^0 &&
-	git checkout B -- b &&
-	echo 8 >>a &&
-	git add -u &&
-	git commit -m "Merge commit B^0 into HEAD" &&
-	git tag E
+test_expect_success 'setup criss-cross + rename/rename/add-source + modify/modify' '
+	test_create_repo rename-rename-add-source &&
+	(
+		cd rename-rename-add-source &&
+
+		printf "lots\nof\nwords\nand\ncontent\n" >a &&
+		git add a &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a c &&
+		printf "2\n3\n4\n5\n6\n7\n" >a &&
+		git add a &&
+		git commit -m C &&
+
+		git checkout B^0 &&
+		git merge --no-commit -s ours C^0 &&
+		git checkout C -- a c &&
+		mv a old_a &&
+		echo 1 >a &&
+		cat old_a >>a &&
+		rm old_a &&
+		git add -u &&
+		git commit -m "Merge commit C^0 into HEAD" &&
+		git tag D &&
+
+		git checkout C^0 &&
+		git merge --no-commit -s ours B^0 &&
+		git checkout B -- b &&
+		echo 8 >>a &&
+		git add -u &&
+		git commit -m "Merge commit B^0 into HEAD" &&
+		git tag E
+	)
 '
 
 test_expect_failure 'detect rename/rename/add-source for virtual merge-base' '
-	git checkout D^0 &&
+	(
+		cd rename-rename-add-source &&
+
+		git checkout D^0 &&
 
-	git merge -s recursive E^0 &&
+		git merge -s recursive E^0 &&
 
-	test 3 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 3 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
-	test $(git rev-parse HEAD:c) = $(git rev-parse A:a) &&
-	test "$(cat a)" = "$(printf "1\n2\n3\n4\n5\n6\n7\n8\n")"
+		test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
+		test $(git rev-parse HEAD:c) = $(git rev-parse A:a) &&
+		test "$(cat a)" = "$(printf "1\n2\n3\n4\n5\n6\n7\n8\n")"
+	)
 '
 
 #
@@ -638,52 +684,56 @@ test_expect_failure 'detect rename/rename/add-source for virtual merge-base' '
 # base of B & C needs to not delete B:c for that to work, though...
 
 test_expect_success 'setup criss-cross+rename/rename/add-dest + simple modify' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	>a &&
-	git add a &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	printf "1\n2\n3\n4\n5\n6\n7\n" >c &&
-	git add c &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a c &&
-	git commit -m C &&
-
-	git checkout B^0 &&
-	git merge --no-commit -s ours C^0 &&
-	git mv b a &&
-	git commit -m "D is like B but renames b back to a" &&
-	git tag D &&
-
-	git checkout B^0 &&
-	git merge --no-commit -s ours C^0 &&
-	git mv b a &&
-	echo 8 >>c &&
-	git add c &&
-	git commit -m "E like D but has mod in c" &&
-	git tag E
+	test_create_repo rename-rename-add-dest &&
+	(
+		cd rename-rename-add-dest &&
+
+		>a &&
+		git add a &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		printf "1\n2\n3\n4\n5\n6\n7\n" >c &&
+		git add c &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a c &&
+		git commit -m C &&
+
+		git checkout B^0 &&
+		git merge --no-commit -s ours C^0 &&
+		git mv b a &&
+		git commit -m "D is like B but renames b back to a" &&
+		git tag D &&
+
+		git checkout B^0 &&
+		git merge --no-commit -s ours C^0 &&
+		git mv b a &&
+		echo 8 >>c &&
+		git add c &&
+		git commit -m "E like D but has mod in c" &&
+		git tag E
+	)
 '
 
 test_expect_success 'virtual merge base handles rename/rename(1to2)/add-dest' '
-	git checkout D^0 &&
+	(
+		cd rename-rename-add-dest &&
+
+		git checkout D^0 &&
 
-	git merge -s recursive E^0 &&
+		git merge -s recursive E^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse HEAD:a) = $(git rev-parse A:a) &&
-	test $(git rev-parse HEAD:c) = $(git rev-parse E:c)
+		test $(git rev-parse HEAD:a) = $(git rev-parse A:a) &&
+		test $(git rev-parse HEAD:c) = $(git rev-parse E:c)
+	)
 '
 
 test_done
diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh
index 411550d2b6..bec0192c3b 100755
--- a/t/t6042-merge-rename-corner-cases.sh
+++ b/t/t6042-merge-rename-corner-cases.sh
@@ -6,31 +6,40 @@ test_description="recursive merge corner cases w/ renames but not criss-crosses"
 . ./test-lib.sh
 
 test_expect_success 'setup rename/delete + untracked file' '
-	echo "A pretty inscription" >ring &&
-	git add ring &&
-	test_tick &&
-	git commit -m beginning &&
-
-	git branch people &&
-	git checkout -b rename-the-ring &&
-	git mv ring one-ring-to-rule-them-all &&
-	test_tick &&
-	git commit -m fullname &&
-
-	git checkout people &&
-	git rm ring &&
-	echo gollum >owner &&
-	git add owner &&
-	test_tick &&
-	git commit -m track-people-instead-of-objects &&
-	echo "Myyy PRECIOUSSS" >ring
+	test_create_repo rename-delete-untracked &&
+	(
+		cd rename-delete-untracked &&
+
+		echo "A pretty inscription" >ring &&
+		git add ring &&
+		test_tick &&
+		git commit -m beginning &&
+
+		git branch people &&
+		git checkout -b rename-the-ring &&
+		git mv ring one-ring-to-rule-them-all &&
+		test_tick &&
+		git commit -m fullname &&
+
+		git checkout people &&
+		git rm ring &&
+		echo gollum >owner &&
+		git add owner &&
+		test_tick &&
+		git commit -m track-people-instead-of-objects &&
+		echo "Myyy PRECIOUSSS" >ring
+	)
 '
 
 test_expect_success "Does git preserve Gollum's precious artifact?" '
-	test_must_fail git merge -s recursive rename-the-ring &&
+	(
+		cd rename-delete-untracked &&
 
-	# Make sure git did not delete an untracked file
-	test -f ring
+		test_must_fail git merge -s recursive rename-the-ring &&
+
+		# Make sure git did not delete an untracked file
+		test -f ring
+	)
 '
 
 # Testcase setup for rename/modify/add-source:
@@ -41,96 +50,116 @@ test_expect_success "Does git preserve Gollum's precious artifact?" '
 # We should be able to merge B & C cleanly
 
 test_expect_success 'setup rename/modify/add-source conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
-	git add a &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	echo 8 >>a &&
-	git add a &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a b &&
-	echo something completely different >a &&
-	git add a &&
-	git commit -m C
+	test_create_repo rename-modify-add-source &&
+	(
+		cd rename-modify-add-source &&
+
+		printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
+		git add a &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		echo 8 >>a &&
+		git add a &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a b &&
+		echo something completely different >a &&
+		git add a &&
+		git commit -m C
+	)
 '
 
 test_expect_failure 'rename/modify/add-source conflict resolvable' '
-	git checkout B^0 &&
+	(
+		cd rename-modify-add-source &&
+
+		git checkout B^0 &&
 
-	git merge -s recursive C^0 &&
+		git merge -s recursive C^0 &&
 
-	test $(git rev-parse B:a) = $(git rev-parse b) &&
-	test $(git rev-parse C:a) = $(git rev-parse a)
+		test $(git rev-parse B:a) = $(git rev-parse b) &&
+		test $(git rev-parse C:a) = $(git rev-parse a)
+	)
 '
 
 test_expect_success 'setup resolvable conflict missed if rename missed' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n" >a &&
-	echo foo >b &&
-	git add a b &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a c &&
-	echo "Completely different content" >a &&
-	git add a &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	echo 6 >>a &&
-	git add a &&
-	git commit -m C
+	test_create_repo break-detection-1 &&
+	(
+		cd break-detection-1 &&
+
+		printf "1\n2\n3\n4\n5\n" >a &&
+		echo foo >b &&
+		git add a b &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a c &&
+		echo "Completely different content" >a &&
+		git add a &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		echo 6 >>a &&
+		git add a &&
+		git commit -m C
+	)
 '
 
 test_expect_failure 'conflict caused if rename not detected' '
-	git checkout -q C^0 &&
-	git merge -s recursive B^0 &&
+	(
+		cd break-detection-1 &&
+
+		git checkout -q C^0 &&
+		git merge -s recursive B^0 &&
 
-	test 3 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 3 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test_line_count = 6 c &&
-	test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
-	test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
+		test_line_count = 6 c &&
+		test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
+		test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
+	)
 '
 
 test_expect_success 'setup conflict resolved wrong if rename missed' '
-	git reset --hard &&
-	git clean -f &&
-
-	git checkout -b D A &&
-	echo 7 >>a &&
-	git add a &&
-	git mv a c &&
-	echo "Completely different content" >a &&
-	git add a &&
-	git commit -m D &&
-
-	git checkout -b E A &&
-	git rm a &&
-	echo "Completely different content" >>a &&
-	git add a &&
-	git commit -m E
+	test_create_repo break-detection-2 &&
+	(
+		cd break-detection-2 &&
+
+		printf "1\n2\n3\n4\n5\n" >a &&
+		echo foo >b &&
+		git add a b &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b D A &&
+		echo 7 >>a &&
+		git add a &&
+		git mv a c &&
+		echo "Completely different content" >a &&
+		git add a &&
+		git commit -m D &&
+
+		git checkout -b E A &&
+		git rm a &&
+		echo "Completely different content" >>a &&
+		git add a &&
+		git commit -m E
+	)
 '
 
 test_expect_failure 'missed conflict if rename not detected' '
-	git checkout -q E^0 &&
-	test_must_fail git merge -s recursive D^0
+	(
+		cd break-detection-2 &&
+
+		git checkout -q E^0 &&
+		test_must_fail git merge -s recursive D^0
+	)
 '
 
 # Tests for undetected rename/add-source causing a file to erroneously be
@@ -145,198 +174,210 @@ test_expect_failure 'missed conflict if rename not detected' '
 #   Commit C: rename a->b, add unrelated a
 
 test_expect_success 'setup undetected rename/add-source causes data loss' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n" >a &&
-	git add a &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a b &&
-	echo foobar >a &&
-	git add a &&
-	git commit -m C
+	test_create_repo break-detection-3 &&
+	(
+		cd break-detection-3 &&
+
+		printf "1\n2\n3\n4\n5\n" >a &&
+		git add a &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a b &&
+		echo foobar >a &&
+		git add a &&
+		git commit -m C
+	)
 '
 
 test_expect_failure 'detect rename/add-source and preserve all data' '
-	git checkout B^0 &&
+	(
+		cd break-detection-3 &&
+
+		git checkout B^0 &&
 
-	git merge -s recursive C^0 &&
+		git merge -s recursive C^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 2 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 2 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test -f a &&
-	test -f b &&
+		test -f a &&
+		test -f b &&
 
-	test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
-	test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
+		test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
+		test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
+	)
 '
 
 test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
-	git checkout C^0 &&
+	(
+		cd break-detection-3 &&
 
-	git merge -s recursive B^0 &&
+		git checkout C^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 2 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		git merge -s recursive B^0 &&
 
-	test -f a &&
-	test -f b &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 2 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
-	test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
+		test -f a &&
+		test -f b &&
+
+		test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
+		test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
+	)
 '
 
 test_expect_success 'setup content merge + rename/directory conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n6\n" >file &&
-	git add file &&
-	test_tick &&
-	git commit -m base &&
-	git tag base &&
-
-	git checkout -b right &&
-	echo 7 >>file &&
-	mkdir newfile &&
-	echo junk >newfile/realfile &&
-	git add file newfile/realfile &&
-	test_tick &&
-	git commit -m right &&
-
-	git checkout -b left-conflict base &&
-	echo 8 >>file &&
-	git add file &&
-	git mv file newfile &&
-	test_tick &&
-	git commit -m left &&
-
-	git checkout -b left-clean base &&
-	echo 0 >newfile &&
-	cat file >>newfile &&
-	git add newfile &&
-	git rm file &&
-	test_tick &&
-	git commit -m left
+	test_create_repo rename-directory-1 &&
+	(
+		cd rename-directory-1 &&
+
+		printf "1\n2\n3\n4\n5\n6\n" >file &&
+		git add file &&
+		test_tick &&
+		git commit -m base &&
+		git tag base &&
+
+		git checkout -b right &&
+		echo 7 >>file &&
+		mkdir newfile &&
+		echo junk >newfile/realfile &&
+		git add file newfile/realfile &&
+		test_tick &&
+		git commit -m right &&
+
+		git checkout -b left-conflict base &&
+		echo 8 >>file &&
+		git add file &&
+		git mv file newfile &&
+		test_tick &&
+		git commit -m left &&
+
+		git checkout -b left-clean base &&
+		echo 0 >newfile &&
+		cat file >>newfile &&
+		git add newfile &&
+		git rm file &&
+		test_tick &&
+		git commit -m left
+	)
 '
 
 test_expect_success 'rename/directory conflict + clean content merge' '
-	git reset --hard &&
-	git reset --hard &&
-	git clean -fdqx &&
+	(
+		cd rename-directory-1 &&
 
-	git checkout left-clean^0 &&
+		git checkout left-clean^0 &&
 
-	test_must_fail git merge -s recursive right^0 &&
+		test_must_fail git merge -s recursive right^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 1 -eq $(git ls-files -u | wc -l) &&
-	test 1 -eq $(git ls-files -o | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 1 -eq $(git ls-files -u | wc -l) &&
+		test 1 -eq $(git ls-files -o | wc -l) &&
 
-	echo 0 >expect &&
-	git cat-file -p base:file >>expect &&
-	echo 7 >>expect &&
-	test_cmp expect newfile~HEAD &&
+		echo 0 >expect &&
+		git cat-file -p base:file >>expect &&
+		echo 7 >>expect &&
+		test_cmp expect newfile~HEAD &&
 
-	test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
+		test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
 
-	test -f newfile/realfile &&
-	test -f newfile~HEAD
+		test -f newfile/realfile &&
+		test -f newfile~HEAD
+	)
 '
 
 test_expect_success 'rename/directory conflict + content merge conflict' '
-	git reset --hard &&
-	git reset --hard &&
-	git clean -fdqx &&
-
-	git checkout left-conflict^0 &&
-
-	test_must_fail git merge -s recursive right^0 &&
-
-	test 4 -eq $(git ls-files -s | wc -l) &&
-	test 3 -eq $(git ls-files -u | wc -l) &&
-	test 1 -eq $(git ls-files -o | wc -l) &&
-
-	git cat-file -p left-conflict:newfile >left &&
-	git cat-file -p base:file    >base &&
-	git cat-file -p right:file   >right &&
-	test_must_fail git merge-file \
-		-L "HEAD:newfile" \
-		-L "" \
-		-L "right^0:file" \
-		left base right &&
-	test_cmp left newfile~HEAD &&
-
-	test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
-	test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
-	test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
-
-	test -f newfile/realfile &&
-	test -f newfile~HEAD
+	(
+		cd rename-directory-1 &&
+
+		git reset --hard &&
+		git reset --hard &&
+		git clean -fdqx &&
+
+		git checkout left-conflict^0 &&
+
+		test_must_fail git merge -s recursive right^0 &&
+
+		test 4 -eq $(git ls-files -s | wc -l) &&
+		test 3 -eq $(git ls-files -u | wc -l) &&
+		test 1 -eq $(git ls-files -o | wc -l) &&
+
+		git cat-file -p left-conflict:newfile >left &&
+		git cat-file -p base:file    >base &&
+		git cat-file -p right:file   >right &&
+		test_must_fail git merge-file \
+			-L "HEAD:newfile" \
+			-L "" \
+			-L "right^0:file" \
+			left base right &&
+		test_cmp left newfile~HEAD &&
+
+		test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
+		test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
+		test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
+
+		test -f newfile/realfile &&
+		test -f newfile~HEAD
+	)
 '
 
 test_expect_success 'setup content merge + rename/directory conflict w/ disappearing dir' '
-	git reset --hard &&
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	mkdir sub &&
-	printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
-	git add sub/file &&
-	test_tick &&
-	git commit -m base &&
-	git tag base &&
-
-	git checkout -b right &&
-	echo 7 >>sub/file &&
-	git add sub/file &&
-	test_tick &&
-	git commit -m right &&
-
-	git checkout -b left base &&
-	echo 0 >newfile &&
-	cat sub/file >>newfile &&
-	git rm sub/file &&
-	mv newfile sub &&
-	git add sub &&
-	test_tick &&
-	git commit -m left
+	test_create_repo rename-directory-2 &&
+	(
+		cd rename-directory-2 &&
+
+		mkdir sub &&
+		printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
+		git add sub/file &&
+		test_tick &&
+		git commit -m base &&
+		git tag base &&
+
+		git checkout -b right &&
+		echo 7 >>sub/file &&
+		git add sub/file &&
+		test_tick &&
+		git commit -m right &&
+
+		git checkout -b left base &&
+		echo 0 >newfile &&
+		cat sub/file >>newfile &&
+		git rm sub/file &&
+		mv newfile sub &&
+		git add sub &&
+		test_tick &&
+		git commit -m left
+	)
 '
 
 test_expect_success 'disappearing dir in rename/directory conflict handled' '
-	git reset --hard &&
-	git clean -fdqx &&
+	(
+		cd rename-directory-2 &&
 
-	git checkout left^0 &&
+		git checkout left^0 &&
 
-	git merge -s recursive right^0 &&
+		git merge -s recursive right^0 &&
 
-	test 1 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 1 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	echo 0 >expect &&
-	git cat-file -p base:sub/file >>expect &&
-	echo 7 >>expect &&
-	test_cmp expect sub &&
+		echo 0 >expect &&
+		git cat-file -p base:sub/file >>expect &&
+		echo 7 >>expect &&
+		test_cmp expect sub &&
 
-	test -f sub
+		test -f sub
+	)
 '
 
 # Test for all kinds of things that can go wrong with rename/rename (2to1):
@@ -352,48 +393,52 @@ test_expect_success 'disappearing dir in rename/directory conflict handled' '
 #   * Nothing else should be present.  Is anything?
 
 test_expect_success 'setup rename/rename (2to1) + modify/modify' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n" >a &&
-	printf "5\n4\n3\n2\n1\n" >b &&
-	git add a b &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a c &&
-	echo 0 >>b &&
-	git add b &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv b c &&
-	echo 6 >>a &&
-	git add a &&
-	git commit -m C
+	test_create_repo rename-rename-2to1 &&
+	(
+		cd rename-rename-2to1 &&
+
+		printf "1\n2\n3\n4\n5\n" >a &&
+		printf "5\n4\n3\n2\n1\n" >b &&
+		git add a b &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a c &&
+		echo 0 >>b &&
+		git add b &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv b c &&
+		echo 6 >>a &&
+		git add a &&
+		git commit -m C
+	)
 '
 
 test_expect_success 'handle rename/rename (2to1) conflict correctly' '
-	git checkout B^0 &&
+	(
+		cd rename-rename-2to1 &&
+
+		git checkout B^0 &&
 
-	test_must_fail git merge -s recursive C^0 >out &&
-	test_i18ngrep "CONFLICT (rename/rename)" out &&
+		test_must_fail git merge -s recursive C^0 >out &&
+		test_i18ngrep "CONFLICT (rename/rename)" out &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 2 -eq $(git ls-files -u | wc -l) &&
-	test 2 -eq $(git ls-files -u c | wc -l) &&
-	test 3 -eq $(git ls-files -o | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 2 -eq $(git ls-files -u | wc -l) &&
+		test 2 -eq $(git ls-files -u c | wc -l) &&
+		test 3 -eq $(git ls-files -o | wc -l) &&
 
-	test ! -f a &&
-	test ! -f b &&
-	test -f c~HEAD &&
-	test -f c~C^0 &&
+		test ! -f a &&
+		test ! -f b &&
+		test -f c~HEAD &&
+		test -f c~C^0 &&
 
-	test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
-	test $(git hash-object c~C^0) = $(git rev-parse B:b)
+		test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
+		test $(git hash-object c~C^0) = $(git rev-parse B:b)
+	)
 '
 
 # Testcase setup for simple rename/rename (1to2) conflict:
@@ -401,44 +446,48 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' '
 #   Commit B: rename a->b
 #   Commit C: rename a->c
 test_expect_success 'setup simple rename/rename (1to2) conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	echo stuff >a &&
-	git add a &&
-	test_tick &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	test_tick &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a c &&
-	test_tick &&
-	git commit -m C
+	test_create_repo rename-rename-1to2 &&
+	(
+		cd rename-rename-1to2 &&
+
+		echo stuff >a &&
+		git add a &&
+		test_tick &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		test_tick &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a c &&
+		test_tick &&
+		git commit -m C
+	)
 '
 
 test_expect_success 'merge has correct working tree contents' '
-	git checkout C^0 &&
+	(
+		cd rename-rename-1to2 &&
+
+		git checkout C^0 &&
 
-	test_must_fail git merge -s recursive B^0 &&
+		test_must_fail git merge -s recursive B^0 &&
 
-	test 3 -eq $(git ls-files -s | wc -l) &&
-	test 3 -eq $(git ls-files -u | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 3 -eq $(git ls-files -s | wc -l) &&
+		test 3 -eq $(git ls-files -u | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
-	test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
-	test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
+		test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
+		test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
+		test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
 
-	test ! -f a &&
-	test $(git hash-object b) = $(git rev-parse A:a) &&
-	test $(git hash-object c) = $(git rev-parse A:a)
+		test ! -f a &&
+		test $(git hash-object b) = $(git rev-parse A:a) &&
+		test $(git hash-object c) = $(git rev-parse A:a)
+	)
 '
 
 # Testcase setup for rename/rename(1to2)/add-source conflict:
@@ -449,130 +498,142 @@ test_expect_success 'merge has correct working tree contents' '
 # Merging of B & C should NOT be clean; there's a rename/rename conflict
 
 test_expect_success 'setup rename/rename(1to2)/add-source conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
-	git add a &&
-	git commit -m A &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	git commit -m B &&
-
-	git checkout -b C A &&
-	git mv a c &&
-	echo something completely different >a &&
-	git add a &&
-	git commit -m C
+	test_create_repo rename-rename-1to2-add-source-1 &&
+	(
+		cd rename-rename-1to2-add-source-1 &&
+
+		printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
+		git add a &&
+		git commit -m A &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		git commit -m B &&
+
+		git checkout -b C A &&
+		git mv a c &&
+		echo something completely different >a &&
+		git add a &&
+		git commit -m C
+	)
 '
 
 test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
-	git checkout B^0 &&
+	(
+		cd rename-rename-1to2-add-source-1 &&
 
-	test_must_fail git merge -s recursive C^0 &&
+		git checkout B^0 &&
 
-	test 4 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test_must_fail git merge -s recursive C^0 &&
 
-	test $(git rev-parse 3:a) = $(git rev-parse C:a) &&
-	test $(git rev-parse 1:a) = $(git rev-parse A:a) &&
-	test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
-	test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
+		test 4 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test -f a &&
-	test -f b &&
-	test -f c
+		test $(git rev-parse 3:a) = $(git rev-parse C:a) &&
+		test $(git rev-parse 1:a) = $(git rev-parse A:a) &&
+		test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
+		test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
+
+		test -f a &&
+		test -f b &&
+		test -f c
+	)
 '
 
 test_expect_success 'setup rename/rename(1to2)/add-source resolvable conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	>a &&
-	git add a &&
-	test_tick &&
-	git commit -m base &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	test_tick &&
-	git commit -m one &&
-
-	git checkout -b C A &&
-	git mv a b &&
-	echo important-info >a &&
-	git add a &&
-	test_tick &&
-	git commit -m two
+	test_create_repo rename-rename-1to2-add-source-2 &&
+	(
+		cd rename-rename-1to2-add-source-2 &&
+
+		>a &&
+		git add a &&
+		test_tick &&
+		git commit -m base &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		test_tick &&
+		git commit -m one &&
+
+		git checkout -b C A &&
+		git mv a b &&
+		echo important-info >a &&
+		git add a &&
+		test_tick &&
+		git commit -m two
+	)
 '
 
 test_expect_failure 'rename/rename/add-source still tracks new a file' '
-	git checkout C^0 &&
-	git merge -s recursive B^0 &&
+	(
+		cd rename-rename-1to2-add-source-2 &&
+
+		git checkout C^0 &&
+		git merge -s recursive B^0 &&
 
-	test 2 -eq $(git ls-files -s | wc -l) &&
-	test 0 -eq $(git ls-files -o | wc -l) &&
+		test 2 -eq $(git ls-files -s | wc -l) &&
+		test 0 -eq $(git ls-files -o | wc -l) &&
 
-	test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
-	test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
+		test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
+		test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
+	)
 '
 
 test_expect_success 'setup rename/rename(1to2)/add-dest conflict' '
-	git rm -rf . &&
-	git clean -fdqx &&
-	rm -rf .git &&
-	git init &&
-
-	echo stuff >a &&
-	git add a &&
-	test_tick &&
-	git commit -m base &&
-	git tag A &&
-
-	git checkout -b B A &&
-	git mv a b &&
-	echo precious-data >c &&
-	git add c &&
-	test_tick &&
-	git commit -m one &&
-
-	git checkout -b C A &&
-	git mv a c &&
-	echo important-info >b &&
-	git add b &&
-	test_tick &&
-	git commit -m two
+	test_create_repo rename-rename-1to2-add-dest &&
+	(
+		cd rename-rename-1to2-add-dest &&
+
+		echo stuff >a &&
+		git add a &&
+		test_tick &&
+		git commit -m base &&
+		git tag A &&
+
+		git checkout -b B A &&
+		git mv a b &&
+		echo precious-data >c &&
+		git add c &&
+		test_tick &&
+		git commit -m one &&
+
+		git checkout -b C A &&
+		git mv a c &&
+		echo important-info >b &&
+		git add b &&
+		test_tick &&
+		git commit -m two
+	)
 '
 
 test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
-	git checkout C^0 &&
-	test_must_fail git merge -s recursive B^0 &&
-
-	test 5 -eq $(git ls-files -s | wc -l) &&
-	test 2 -eq $(git ls-files -u b | wc -l) &&
-	test 2 -eq $(git ls-files -u c | wc -l) &&
-	test 4 -eq $(git ls-files -o | wc -l) &&
-
-	test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
-	test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
-	test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
-	test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
-	test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
-
-	test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
-	test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
-	test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
-	test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
-
-	test ! -f b &&
-	test ! -f c
+	(
+		cd rename-rename-1to2-add-dest &&
+
+		git checkout C^0 &&
+		test_must_fail git merge -s recursive B^0 &&
+
+		test 5 -eq $(git ls-files -s | wc -l) &&
+		test 2 -eq $(git ls-files -u b | wc -l) &&
+		test 2 -eq $(git ls-files -u c | wc -l) &&
+		test 4 -eq $(git ls-files -o | wc -l) &&
+
+		test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
+		test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
+		test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
+		test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
+		test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
+
+		test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
+		test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
+		test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
+		test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
+
+		test ! -f b &&
+		test ! -f c
+	)
 '
 
 test_done
-- 
2.17.0.1.gda85003413


^ permalink raw reply related	[relevance 3%]

* [PATCH v9 4/4] worktree: teach "add" to check out existing branches
  @ 2018-04-24 21:56  9%                 ` Thomas Gummerer
  0 siblings, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-04-24 21:56 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 13 +++++++++++--
 t/t2025-worktree-add.sh        | 26 +++++++++++++++++++-------
 3 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..5d54f36a71 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, the new worktree is associated with a branch
+(call it `<branch>`) named after `$(basename <path>)`.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` does exist, it will be
+checked out in the new worktree, if it's not checked out anywhere
+else, otherwise the command will refuse to create the worktree (unless
+`--force` is used).
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 6bd32b6090..d3aeb4877d 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -391,8 +391,17 @@ static const char *dwim_branch(const char *path, const char **new_branch)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	*new_branch = xstrndup(s, n);
-	UNLEAK(*new_branch);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	UNLEAK(branchname);
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		strbuf_release(&ref);
+		return branchname;
+	}
+
+	*new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..ad38507d00 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,25 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
-	test_commit c1 &&
-	test_commit c2 &&
-	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
-	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+test_expect_success '"add" checks out existing branch of dwimd name' '
+	git branch dwim HEAD~1 &&
+	git worktree add dwim &&
+	test_cmp_rev HEAD~1 dwim &&
+	(
+		cd dwim &&
+		test_cmp_rev HEAD dwim
+	)
+'
+
+test_expect_success '"add <path>" dwim fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
+'
+
+test_expect_success '"add --force" with existing dwimd name doesnt die' '
+	git checkout test-branch &&
+	git worktree add --force test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.16.1.74.g7afd1c25cc.dirty


^ permalink raw reply related	[relevance 9%]

* [PATCH v8 4/4] worktree: teach "add" to check out existing branches
  @ 2018-04-23 19:38  9%               ` Thomas Gummerer
    1 sibling, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-04-23 19:38 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 30 ++++++++++++++++++++++++------
 t/t2025-worktree-add.sh        | 26 +++++++++++++++++++-------
 3 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..5d54f36a71 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, the new worktree is associated with a branch
+(call it `<branch>`) named after `$(basename <path>)`.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` does exist, it will be
+checked out in the new worktree, if it's not checked out anywhere
+else, otherwise the command will refuse to create the worktree (unless
+`--force` is used).
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index bd4cf4583f..d52495f312 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -356,9 +356,12 @@ static int add_worktree(const char *path, const char *refname,
 static void print_preparing_worktree_line(int detach,
 					  const char *branch,
 					  const char *new_branch,
-					  const char *new_branch_force)
+					  const char *new_branch_force,
+					  int checkout_existing_branch)
 {
-	if (new_branch_force) {
+	if (checkout_existing_branch) {
+		printf_ln(_("Preparing worktree (checking out '%s')"), branch);
+	} else if (new_branch_force) {
 		struct commit *commit = lookup_commit_reference_by_name(new_branch_force);
 		if (!commit)
 			printf_ln(_("Preparing worktree (new branch '%s')"), new_branch_force);
@@ -387,11 +390,23 @@ static void print_preparing_worktree_line(int detach,
 	}
 }
 
-static const char *dwim_branch(const char *path, const char **new_branch)
+static const char *dwim_branch(const char *path, const char **new_branch,
+			       int *checkout_existing_branch)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	*new_branch = xstrndup(s, n);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		*checkout_existing_branch = 1;
+		strbuf_release(&ref);
+		UNLEAK(branchname);
+		return branchname;
+	}
+
+	*new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
@@ -406,6 +421,7 @@ static int add(int ac, const char **av, const char *prefix)
 	struct add_opts opts;
 	const char *new_branch_force = NULL;
 	char *path;
+	int checkout_existing_branch = 0;
 	const char *branch;
 	const char *new_branch = NULL;
 	const char *opt_track = NULL;
@@ -453,7 +469,8 @@ static int add(int ac, const char **av, const char *prefix)
 	}
 
 	if (ac < 2 && !new_branch && !opts.detach) {
-		const char *s = dwim_branch(path, &new_branch);
+		const char *s = dwim_branch(path, &new_branch,
+					    &checkout_existing_branch);
 		if (s)
 			branch = s;
 	}
@@ -473,7 +490,8 @@ static int add(int ac, const char **av, const char *prefix)
 		}
 	}
 
-	print_preparing_worktree_line(opts.detach, branch, new_branch, new_branch_force);
+	print_preparing_worktree_line(opts.detach, branch, new_branch, new_branch_force,
+				      checkout_existing_branch);
 
 	if (new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..ad38507d00 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,25 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
-	test_commit c1 &&
-	test_commit c2 &&
-	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
-	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+test_expect_success '"add" checks out existing branch of dwimd name' '
+	git branch dwim HEAD~1 &&
+	git worktree add dwim &&
+	test_cmp_rev HEAD~1 dwim &&
+	(
+		cd dwim &&
+		test_cmp_rev HEAD dwim
+	)
+'
+
+test_expect_success '"add <path>" dwim fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
+'
+
+test_expect_success '"add --force" with existing dwimd name doesnt die' '
+	git checkout test-branch &&
+	git worktree add --force test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.16.1.74.g7afd1c25cc.dirty


^ permalink raw reply related	[relevance 9%]

* Re: [PATCH/RFC] completion: complete all possible -no-<options>
  2018-04-17 18:13  3% [PATCH/RFC] completion: complete all possible -no-<options> Nguyễn Thái Ngọc Duy
@ 2018-04-23  5:36  0% ` Eric Sunshine
  0 siblings, 0 replies; 200+ results
From: Eric Sunshine @ 2018-04-23  5:36 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Tue, Apr 17, 2018 at 2:13 PM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> The problem with completing --no- form is that the number of
> completable options now usually doubles, taking precious screen space
> and also making it hard to find the option you want.
>
> So the other half of this patch, the part in git-completion.bash, is
> to uncomplete --no- options. When you do "git checkout --<tab>",
> instead of displaying all --no- options, this patch simply displays
> one item: the --no- prefix. If you do "git checkout --no-<tab>" then
> all negative options are displayed. This helps reduce completable
> options quite efficiently.
>
> After all this "git checkout --<tab>" now looks like this
>
>     > ~/w/git $ git co --
>     --conflict=                   --orphan=
>     --detach                      --ours
>     --ignore-other-worktrees      --patch
>     --ignore-skip-worktree-bits   --progress
>     --merge                       --quiet
>     --no-                         --recurse-submodules
>     --no-detach                   --theirs
>     --no-quiet                    --track
>     --no-track

I haven't looked at the implementation, so this may be an entirely
stupid suggestion, but would it be possible to instead render the
completions as?

    % git checkout --<tab>
    --[no-]conflict=                   --[no-]patch
    --[no-]detach                      --[no-]progress
    --[no-]ignore-other-worktrees      --[no-]quiet
    --[no-]ignore-skip-worktree-bits   --[no-]recurse-submodules
    --[no-]merge                       --theirs
    --[no-]orphan=                     --[no-]track
    --ours

This would address the problem of the --no-* options taking double the
screen space.

It's also more intuitive than that lone and somewhat weird-looking
"--no-" suggestion.

^ permalink raw reply	[relevance 0%]

* [PATCH/RFC] completion: complete all possible -no-<options>
@ 2018-04-17 18:13  3% Nguyễn Thái Ngọc Duy
  2018-04-23  5:36  0% ` Eric Sunshine
  0 siblings, 1 reply; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-04-17 18:13 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This is not a complete topic but I'd like to present the problem and
my approach to see if it's a good way to go.

We have started recently to rely on parse-options to help complete
options. One of the leftover items is allowing completing --no- form.
This patch enables that (some options should not have --no- form, but
that's easy not included here).

The problem with completing --no- form is that the number of
completable options now usually doubles, taking precious screen space
and also making it hard to find the option you want.

So the other half of this patch, the part in git-completion.bash, is
to uncomplete --no- options. When you do "git checkout --<tab>",
instead of displaying all --no- options, this patch simply displays
one item: the --no- prefix. If you do "git checkout --no-<tab>" then
all negative options are displayed. This helps reduce completable
options quite efficiently.

Of course life is not that simple, we do have --no- options by default
sometimes (taking priority over the positive form), e.g. "git clone
--no-checkout". Collapsing all --no-options into --no- would be a
regression.

To avoid it, the order of options --git-completion-helper returns does
matter. The first 4 negative options are not collapsed. Only options
after the 4th are. Extra --no- options are always printed at the end,
after all the --no- defined in struct option, this kinda works. Not
pretty but works.

After all this "git checkout --<tab>" now looks like this

    > ~/w/git $ git co --
    --conflict=                   --orphan=
    --detach                      --ours 
    --ignore-other-worktrees      --patch 
    --ignore-skip-worktree-bits   --progress 
    --merge                       --quiet 
    --no-                         --recurse-submodules 
    --no-detach                   --theirs 
    --no-quiet                    --track 
    --no-track                    

and all the no options

    > ~/w/git $ git co --no-
    --no-conflict                    --no-patch 
    --no-detach                      --no-progress 
    --no-ignore-other-worktrees      --no-quiet 
    --no-ignore-skip-worktree-bits   --no-recurse-submodules 
    --no-merge                       --no-track 
    --no-orphan                      

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 contrib/completion/git-completion.bash | 25 +++++++++++++++-
 parse-options.c                        | 40 +++++++++++++++++++++++---
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index a757073945..85b9f24465 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -266,7 +266,7 @@ __gitcomp ()
 	case "$cur_" in
 	--*=)
 		;;
-	*)
+	--no-*)
 		local c i=0 IFS=$' \t\n'
 		for c in $1; do
 			c="$c${4-}"
@@ -279,6 +279,29 @@ __gitcomp ()
 			fi
 		done
 		;;
+	*)
+		local c i=0 IFS=$' \t\n' n=0
+		for c in $1; do
+			c="$c${4-}"
+			if [[ $c == "$cur_"* ]]; then
+				case $c in
+				--*=*|*.) ;;
+				--no-*)
+					n=$(($n+1))
+					if [ "$n" -eq 4 ]; then
+						c="--no-${4-} "
+					elif [ "$n" -gt 4 ]; then
+						continue
+					else
+						c="$c "
+					fi
+					;;
+				*) c="$c " ;;
+				esac
+				COMPREPLY[i++]="${2-}$c"
+			fi
+		done
+		;;
 	esac
 }
 
diff --git a/parse-options.c b/parse-options.c
index 0f7059a8ab..f6cd7ca8d2 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -427,13 +427,11 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
 	parse_options_check(options);
 }
 
-/*
- * TODO: we are not completing the --no-XXX form yet because there are
- * many options that do not suppress it properly.
- */
 static int show_gitcomp(struct parse_opt_ctx_t *ctx,
 			const struct option *opts)
 {
+	const struct option *original_opts = opts;
+
 	for (; opts->type != OPTION_END; opts++) {
 		const char *suffix = "";
 
@@ -465,6 +463,40 @@ static int show_gitcomp(struct parse_opt_ctx_t *ctx,
 			suffix = "=";
 		printf(" --%s%s", opts->long_name, suffix);
 	}
+	for (opts = original_opts; opts->type != OPTION_END; opts++) {
+		int has_unset_form = 0;
+
+		if (!opts->long_name)
+			continue;
+		if (opts->flags & (PARSE_OPT_HIDDEN | PARSE_OPT_NOCOMPLETE))
+			continue;
+		if (opts->flags & PARSE_OPT_NONEG)
+			continue;
+
+		switch (opts->type) {
+		case OPTION_STRING:
+		case OPTION_FILENAME:
+		case OPTION_INTEGER:
+		case OPTION_MAGNITUDE:
+		case OPTION_CALLBACK:
+		case OPTION_BIT:
+		case OPTION_NEGBIT:
+		case OPTION_COUNTUP:
+		case OPTION_SET_INT:
+			has_unset_form = 1;
+			break;
+		default:
+			break;
+		}
+		if (has_unset_form) {
+			const char *name;
+
+			if (skip_prefix(opts->long_name, "no-", &name))
+				printf(" --%s", name);
+			else
+				printf(" --no-%s", opts->long_name);
+		}
+	}
 	fputc('\n', stdout);
 	exit(0);
 }
-- 
2.17.0.367.g5dd2e386c3


^ permalink raw reply related	[relevance 3%]

* [PATCH v7 4/4] worktree: teach "add" to check out existing branches
  @ 2018-04-15 20:29  9%             ` Thomas Gummerer
    1 sibling, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-04-15 20:29 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 30 ++++++++++++++++++++++++------
 t/t2025-worktree-add.sh        | 26 +++++++++++++++++++-------
 3 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..5d54f36a71 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, the new worktree is associated with a branch
+(call it `<branch>`) named after `$(basename <path>)`.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` does exist, it will be
+checked out in the new worktree, if it's not checked out anywhere
+else, otherwise the command will refuse to create the worktree (unless
+`--force` is used).
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 893139629a..f5a5283b39 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -355,9 +355,12 @@ static int add_worktree(const char *path, const char *refname,
 
 static void print_preparing_worktree_line(const char *branch,
 					  const char *new_branch,
-					  const char *new_branch_force)
+					  const char *new_branch_force,
+					  int checkout_existing_branch)
 {
-	if (new_branch_force) {
+	if (checkout_existing_branch) {
+		printf_ln(_("Preparing worktree (checking out '%s')"), branch);
+	} else if (new_branch_force) {
 		struct commit *commit = lookup_commit_reference_by_name(new_branch_force);
 		if (!commit)
 			printf_ln(_("Preparing worktree (new branch '%s')"), new_branch_force);
@@ -378,11 +381,23 @@ static void print_preparing_worktree_line(const char *branch,
 	}
 }
 
-static const char *dwim_branch(const char *path, const char **new_branch)
+static const char *dwim_branch(const char *path, const char **new_branch,
+			       int *checkout_existing_branch)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	*new_branch = xstrndup(s, n);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		*checkout_existing_branch = 1;
+		strbuf_release(&ref);
+		UNLEAK(branchname);
+		return branchname;
+	}
+
+	*new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
@@ -397,6 +412,7 @@ static int add(int ac, const char **av, const char *prefix)
 	struct add_opts opts;
 	const char *new_branch_force = NULL;
 	char *path;
+	int checkout_existing_branch = 0;
 	const char *branch;
 	const char *new_branch = NULL;
 	const char *opt_track = NULL;
@@ -444,7 +460,8 @@ static int add(int ac, const char **av, const char *prefix)
 	}
 
 	if (ac < 2 && !new_branch && !opts.detach) {
-		const char *s = dwim_branch(path, &new_branch);
+		const char *s = dwim_branch(path, &new_branch,
+					    &checkout_existing_branch);
 		if (s)
 			branch = s;
 	}
@@ -464,7 +481,8 @@ static int add(int ac, const char **av, const char *prefix)
 		}
 	}
 
-	print_preparing_worktree_line(branch, new_branch, new_branch_force);
+	print_preparing_worktree_line(branch, new_branch, new_branch_force,
+				      checkout_existing_branch);
 
 	if (new_branch) {
 		struct child_process cp = CHILD_PROCESS_INIT;
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..ad38507d00 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,25 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
-	test_commit c1 &&
-	test_commit c2 &&
-	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
-	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+test_expect_success '"add" checks out existing branch of dwimd name' '
+	git branch dwim HEAD~1 &&
+	git worktree add dwim &&
+	test_cmp_rev HEAD~1 dwim &&
+	(
+		cd dwim &&
+		test_cmp_rev HEAD dwim
+	)
+'
+
+test_expect_success '"add <path>" dwim fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
+'
+
+test_expect_success '"add --force" with existing dwimd name doesnt die' '
+	git checkout test-branch &&
+	git worktree add --force test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.17.0.252.gfe0a9eaf31


^ permalink raw reply related	[relevance 9%]

* [PATCH v6 6/6] worktree: teach "add" to check out existing branches
  @ 2018-03-31 15:18  9%           ` Thomas Gummerer
    1 sibling, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-03-31 15:18 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 22 +++++++++++++++++++---
 t/t2025-worktree-add.sh        | 25 ++++++++++++++++++-------
 3 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..eaa6bf713f 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, a worktree with a branch named after
+`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` exists in the repository,
+it will be checked out in the new worktree, if it's not checked out
+anywhere else, otherwise the command will refuse to create the
+worktree (unless `--force` is used).
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 47189d50dd..511d0aa370 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -363,11 +363,23 @@ static int add_worktree(const char *path, const char *refname,
 	return ret;
 }
 
-static const char *dwim_branch(const char *path, const char **new_branch)
+static const char *dwim_branch(const char *path, const char **new_branch,
+			       int *checkout_existing_branch)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	*new_branch = xstrndup(s, n);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		*checkout_existing_branch = 1;
+		strbuf_release(&ref);
+		UNLEAK(branchname);
+		return branchname;
+	}
+
+	*new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
@@ -385,6 +397,7 @@ static int add(int ac, const char **av, const char *prefix)
 	const char *branch;
 	const char *new_branch = NULL;
 	const char *opt_track = NULL;
+	int checkout_existing_branch = 0;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &new_branch, N_("branch"),
@@ -429,7 +442,8 @@ static int add(int ac, const char **av, const char *prefix)
 	}
 
 	if (ac < 2 && !new_branch && !opts.detach) {
-		const char *s = dwim_branch(path, &new_branch);
+		const char *s = dwim_branch(path, &new_branch,
+					    &checkout_existing_branch);
 		if (s)
 			branch = s;
 	}
@@ -464,6 +478,8 @@ static int add(int ac, const char **av, const char *prefix)
 		if (run_command(&cp))
 			return -1;
 		branch = new_branch;
+	} else if (checkout_existing_branch) {
+		  fprintf_ln(stderr, _("Checking out branch '%s'"), branch);
 	} else if (opt_track) {
 		die(_("--[no-]track can only be used if a new branch is created"));
 	}
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..f72cb0eb0b 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,24 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
-	test_commit c1 &&
-	test_commit c2 &&
-	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
-	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+test_expect_success '"add" checks out existing branch of dwimd name' '
+	git branch dwim HEAD~1 &&
+	git worktree add dwim &&
+	test_cmp_rev HEAD~1 dwim &&
+	(
+		cd dwim &&
+		test_cmp_rev dwim HEAD
+	)
+'
+
+test_expect_success '"add <path>" dwim fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
+'
+
+test_expect_success '"add --force" with existing dwimd name doesnt die' '
+	git worktree add --force test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.16.1.78.ga2082135d8


^ permalink raw reply related	[relevance 9%]

* Re: [PATCH v5 5/6] worktree: teach "add" to check out existing branches
  2018-03-27  9:04  7%           ` Eric Sunshine
@ 2018-03-30 14:04  0%             ` Thomas Gummerer
  0 siblings, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-03-30 14:04 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git List, Nguyễn Thái Ngọc Duy, Junio C Hamano

On 03/27, Eric Sunshine wrote:
> On Sun, Mar 25, 2018 at 9:49 AM, Thomas Gummerer <t.gummerer@gmail.com> wrote:
> > Currently 'git worktree add <path>' creates a new branch named after the
> > basename of the path by default.  If a branch with that name already
> > exists, the command refuses to do anything, unless the '--force' option
> > is given.
> >
> > However we can do a little better than that, and check the branch out if
> > it is not checked out anywhere else.  This will help users who just want
> > to check an existing branch out into a new worktree, and save a few
> > keystrokes.
> > [...]
> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> > ---
> > diff --git a/builtin/worktree.c b/builtin/worktree.c
> > @@ -317,7 +318,10 @@ static int add_worktree(const char *path, const char *refname,
> > -       if (opts->new_branch)
> > +       if (opts->checkout_existing_branch)
> > +               fprintf_ln(stderr, _("checking out branch '%s'"),
> > +                          refname);
> 
> This fprintf_ln() can easily fit on one line; no need to wrap
> 'refname' to the next one.
> 
> Not worth a re-roll, though.
> 
> > +       else if (opts->new_branch)
> >                 fprintf_ln(stderr, _("creating branch '%s'"), opts->new_branch);
> > diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> > @@ -198,13 +198,26 @@ test_expect_success '"add" with <branch> omitted' '
> > -test_expect_success '"add" auto-vivify does not clobber existing branch' '
> > +test_expect_success '"add" checks out existing branch of dwimd name' '
> >         test_commit c1 &&
> >         test_commit c2 &&
> >         git branch precious HEAD~1 &&
> > -       test_must_fail git worktree add precious &&
> > +       git worktree add precious &&
> >         test_cmp_rev HEAD~1 precious &&
> > -       test_path_is_missing precious
> > +       (
> > +               cd precious &&
> > +               test_cmp_rev precious HEAD
> > +       )
> > +'
> 
> Looking at this more closely, once it stops being a "don't clobber
> precious branch" test, it's doing more than it needs to do, thus is
> confusing for future readers. The setup -- creating two commits and
> making "precious" point one commit back -- was very intentional and
> allowed the test to verify not only that the worktree wasn't created
> but that "precious" didn't change to reference a different commit.
> However, _none_ of this matters once it becomes a dwim'ing test; the
> unnecessary code is confusing since it doesn't make sense in the
> context of dwim'ing. I _think_ the entire test can collapse to:
> 
>     git branch existing &&
>     git worktree add existing &&
>     (
>         cd existing &&
>         test_cmp_rev existing HEAD
>     )
> 
> In other words, this patch should drop the "precious" test altogether
> and just introduce a new dwim'ing test (and drop patch 6/6).
> 
> I do think that with the potential confusion to future readers, this
> does deserve a re-roll.

Hmm I do think that it's important to have the branch we create the
new working tree from different from the branch of the main working
tree, to make sure we don't accidentally overwrite an existing branch,
and to show that the new branch is checked out.

Maybe I'm overly paranoid though?

> > +test_expect_success '"add" auto-vivify fails with checked out branch' '
> > +       git checkout -b test-branch &&
> > +       test_must_fail git worktree add test-branch &&
> > +       test_path_is_missing test-branch
> > +'
> > +
> > +test_expect_success '"add --force" with existing dwimd name doesnt die' '
> > +       git worktree add --force test-branch
> >  '

^ permalink raw reply	[relevance 0%]

* [PATCH] l10n: de.po: translate 132 new messages
@ 2018-03-28  5:55  1% Ralf Thielow
  0 siblings, 0 replies; 200+ results
From: Ralf Thielow @ 2018-03-28  5:55 UTC (permalink / raw)
  To: git
  Cc: Thomas Rast, Jan Krüger, Christian Stimming, Phillip Szelat,
	Matthias Rüster, Magnus Görlitz, Ralf Thielow

Translate 132 new message came from git.pot update in abc8de64d (l10n:
git.pot: v2.17.0 round 1 (132 new, 44 removed)).

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 po/de.po | 455 +++++++++++++++++++++++++------------------------------
 1 file changed, 209 insertions(+), 246 deletions(-)

diff --git a/po/de.po b/po/de.po
index 852c02a9b..793bd2a80 100644
--- a/po/de.po
+++ b/po/de.po
@@ -1654,15 +1654,14 @@ msgstr "externes Diff-Programm unerwartet beendet, angehalten bei %s"
 #: diff.c:4146
 msgid "--name-only, --name-status, --check and -s are mutually exclusive"
 msgstr ""
 "--name-only, --name-status, --check und -s schließen sich gegenseitig aus"
 
 #: diff.c:4149
-#, fuzzy
 msgid "-G, -S and --find-object are mutually exclusive"
-msgstr "-b, -B und --detach schließen sich gegenseitig aus"
+msgstr "-G, -S und --find-object schließen sich gegenseitig aus"
 
 #: diff.c:4237
 msgid "--follow requires exactly one pathspec"
 msgstr "--follow erfordert genau eine Pfadspezifikation"
 
 #: diff.c:4403
@@ -1695,15 +1694,15 @@ msgid ""
 "you may want to set your %s variable to at least %d and retry the command."
 msgstr ""
 "Sie könnten die Variable %s auf mindestens %d setzen und den Befehl\n"
 "erneut versuchen."
 
 #: dir.c:1866
-#, fuzzy, c-format
+#, c-format
 msgid "could not open directory '%s'"
-msgstr "Konnte Verzeichnis '%s' nicht erstellen."
+msgstr "Konnte Verzeichnis '%s' nicht öffnen."
 
 #: dir.c:2108
 msgid "failed to get kernel name and information"
 msgstr "Fehler beim Sammeln von Namen und Informationen zum Kernel"
 
 #: dir.c:2232
@@ -1731,27 +1730,25 @@ msgstr "Hinweis: Warte auf das Schließen der Datei durch Ihren Editor...%c"
 msgid "Filtering content"
 msgstr "Filtere Inhalt"
 
 #: entry.c:435
 #, c-format
 msgid "could not stat file '%s'"
-msgstr "konnte Datei '%s' nicht lesen"
+msgstr "Konnte Datei '%s' nicht lesen."
 
 #: fetch-object.c:17
-#, fuzzy
 msgid "Remote with no URL"
-msgstr "git archive: Externes Archiv ohne URL"
+msgstr "Remote-Repository ohne URL"
 
 #: fetch-pack.c:253
 msgid "git fetch-pack: expected shallow list"
 msgstr "git fetch-pack: erwartete shallow-Liste"
 
 #: fetch-pack.c:265
-#, fuzzy
 msgid "git fetch-pack: expected ACK/NAK, got a flush packet"
-msgstr "git fetch-pack: ACK/NAK erwartet, '%s' bekommen"
+msgstr "git fetch-pack: ACK/NAK erwartet, Flush-Paket bekommen"
 
 #: fetch-pack.c:284 builtin/archive.c:63
 #, c-format
 msgid "remote error: %s"
 msgstr "Fehler am anderen Ende: %s"
 
@@ -1883,15 +1880,14 @@ msgstr "Server unterstützt allow-reachable-sha1-in-want"
 
 #: fetch-pack.c:979
 msgid "Server supports ofs-delta"
 msgstr "Server unterstützt ofs-delta"
 
 #: fetch-pack.c:985
-#, fuzzy
 msgid "Server supports filter"
-msgstr "Server unterstützt ofs-delta"
+msgstr "Server unterstützt Filter"
 
 #: fetch-pack.c:993
 #, c-format
 msgid "Server version is %.*s"
 msgstr "Server-Version ist %.*s"
 
@@ -2104,19 +2100,18 @@ msgstr "Name besteht nur aus nicht erlaubten Zeichen: %s"
 #: ident.c:416 builtin/commit.c:582
 #, c-format
 msgid "invalid date format: %s"
 msgstr "Ungültiges Datumsformat: %s"
 
 #: list-objects-filter-options.c:36
-#, fuzzy
 msgid "multiple filter-specs cannot be combined"
-msgstr "Mehrere Arten von Objekt-Filtern können nicht kombiniert werden."
+msgstr "Mehrere filter-specs können nicht kombiniert werden."
 
 #: list-objects-filter-options.c:126
 msgid "cannot change partial clone promisor remote"
-msgstr ""
+msgstr "Kann Remote-Repository für partielles Klonen nicht ändern."
 
 #: lockfile.c:151
 #, c-format
 msgid ""
 "Unable to create '%s.lock': %s.\n"
 "\n"
@@ -2964,20 +2959,20 @@ msgstr "  (benutzen Sie \"git branch --unset-upstream\" zum Beheben)\n"
 #: remote.c:2139
 #, c-format
 msgid "Your branch is up to date with '%s'.\n"
 msgstr "Ihr Branch ist auf demselben Stand wie '%s'.\n"
 
 #: remote.c:2143
-#, fuzzy, c-format
+#, c-format
 msgid "Your branch and '%s' refer to different commits.\n"
-msgstr "Ihr Branch ist %2$d Commit vor '%1$s'.\n"
+msgstr "Ihr Branch und '%s' zeigen auf unterschiedliche Commits.\n"
 
 #: remote.c:2146
 #, c-format
 msgid "  (use \"%s\" for details)\n"
-msgstr ""
+msgstr "  (benutzen Sie \"%s\" für Details)\n"
 
 #: remote.c:2150
 #, c-format
 msgid "Your branch is ahead of '%s' by %d commit.\n"
 msgid_plural "Your branch is ahead of '%s' by %d commits.\n"
 msgstr[0] "Ihr Branch ist %2$d Commit vor '%1$s'.\n"
@@ -3048,15 +3043,14 @@ msgid ""
 msgstr ""
 "Der '%s' Hook wurde ignoriert, weil er nicht als ausführbar markiert ist.\n"
 "Sie können diese Warnung mit `git config advice.ignoredHook false` "
 "deaktivieren."
 
 #: send-pack.c:141
-#, fuzzy
 msgid "unexpected flush packet while reading remote unpack status"
-msgstr "Konnte Status des Entpackens der Gegenseite nicht parsen: %s"
+msgstr "Unerwartetes Flush-Paket beim Lesen des Remote-Unpack-Status."
 
 #: send-pack.c:143
 #, c-format
 msgid "unable to parse remote unpack status: %s"
 msgstr "Konnte Status des Entpackens der Gegenseite nicht parsen: %s"
 
@@ -3088,15 +3082,15 @@ msgstr "die Gegenseite unterstützt keinen atomaren Versand (\"--atomic push\")"
 
 #: send-pack.c:440
 msgid "the receiving end does not support push options"
 msgstr "die Gegenseite unterstützt keine Push-Optionen"
 
 #: sequencer.c:158
-#, fuzzy, c-format
+#, c-format
 msgid "invalid commit message cleanup mode '%s'"
-msgstr "Ungültiger \"cleanup\" Modus %s"
+msgstr "Ungültiger \"cleanup\"-Modus '%s' für Commit-Beschreibungen."
 
 #: sequencer.c:267
 msgid "revert"
 msgstr "Revert"
 
 #: sequencer.c:269
@@ -3144,13 +3138,13 @@ msgstr "Konnte nicht nach '%s' schreiben."
 #: sequencer.c:353
 #, c-format
 msgid "could not write eol to '%s'"
 msgstr "Konnte EOL nicht nach '%s' schreiben."
 
 #: sequencer.c:356 sequencer.c:2128 sequencer.c:2252
-#, fuzzy, c-format
+#, c-format
 msgid "failed to finalize '%s'"
 msgstr "Fehler beim Fertigstellen von '%s'."
 
 #: sequencer.c:379 sequencer.c:1340 sequencer.c:2148 builtin/am.c:259
 #: builtin/commit.c:722 builtin/merge.c:1047
 #, c-format
@@ -3217,15 +3211,14 @@ msgstr ""
 "\n"
 "Im Anschluss führen Sie zum Fortfahren aus:\n"
 "\n"
 "  git rebase --continue\n"
 
 #: sequencer.c:915
-#, fuzzy
 msgid "'prepare-commit-msg' hook failed"
-msgstr "commit-msg Hook überprüfen"
+msgstr "'prepare-commit-msg' Hook fehlgeschlagen."
 
 #: sequencer.c:922
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
 "You can suppress this message by setting them explicitly. Run the\n"
@@ -3296,38 +3289,36 @@ msgstr "losgelöster HEAD"
 
 #: sequencer.c:1029
 msgid " (root-commit)"
 msgstr " (Basis-Commit)"
 
 #: sequencer.c:1050
-#, fuzzy
 msgid "could not parse HEAD"
-msgstr "Konnte HEAD nicht lesen"
+msgstr "Konnte HEAD nicht parsen."
 
 #: sequencer.c:1052
-#, fuzzy, c-format
+#, c-format
 msgid "HEAD %s is not a commit!"
-msgstr "%s %s ist kein Commit!"
+msgstr "HEAD %s ist kein Commit!"
 
 #: sequencer.c:1056 builtin/commit.c:1491
 msgid "could not parse HEAD commit"
 msgstr "Konnte Commit von HEAD nicht analysieren."
 
 #: sequencer.c:1107 sequencer.c:1673
-#, fuzzy
 msgid "unable to parse commit author"
-msgstr "Konnte Commit '%s' nicht parsen."
+msgstr "Konnte Commit-Autor nicht parsen."
 
 #: sequencer.c:1117 builtin/am.c:1630 builtin/merge.c:643
 msgid "git write-tree failed to write a tree"
 msgstr "\"git write-tree\" schlug beim Schreiben eines \"Tree\"-Objektes fehl"
 
 #: sequencer.c:1134 sequencer.c:1186
-#, fuzzy, c-format
+#, c-format
 msgid "unable to read commit message from '%s'"
-msgstr "Konnte Commit-Beschreibung von %s nicht lesen."
+msgstr "Konnte Commit-Beschreibung von '%s' nicht lesen."
 
 #: sequencer.c:1154 builtin/am.c:1650 builtin/commit.c:1594 builtin/merge.c:826
 #: builtin/merge.c:851
 msgid "failed to write commit object"
 msgstr "Fehler beim Schreiben des Commit-Objektes."
 
@@ -3808,15 +3799,15 @@ msgstr "Konnte Commit '%s' nicht parsen."
 
 #: sequencer.c:3401
 msgid "the script was already rearranged."
 msgstr "Das Script wurde bereits umgeordnet."
 
 #: setup.c:122
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is outside repository"
-msgstr "%s: '%s' liegt außerhalb des Repositories"
+msgstr "'%s' liegt außerhalb des Repositories."
 
 #: setup.c:171
 #, c-format
 msgid ""
 "%s: no such path in the working tree.\n"
 "Use 'git <command> -- <path>...' to specify paths that do not exist locally."
@@ -3835,15 +3826,15 @@ msgstr ""
 "mehrdeutiges Argument '%s': unbekannter Commit oder Pfad existiert nicht\n"
 "im Arbeitsverzeichnis\n"
 "Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:\n"
 "'git <Befehl> [<Commit>...] -- [<Datei>...]'"
 
 #: setup.c:233
-#, fuzzy, c-format
+#, c-format
 msgid "option '%s' must come before non-option arguments"
-msgstr "das Parsen nach dem ersten Argument, was keine Option ist, stoppen"
+msgstr "Die Option '%s' muss vor den Argumenten kommen, die keine Optionen sind."
 
 #: setup.c:252
 #, c-format
 msgid ""
 "ambiguous argument '%s': both revision and filename\n"
 "Use '--' to separate paths from revisions, like this:\n"
@@ -3851,131 +3842,126 @@ msgid ""
 msgstr ""
 "mehrdeutiges Argument '%s': sowohl Commit als auch Dateiname\n"
 "Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:\n"
 "'git <Befehl> [<Commit>...] -- [<Datei>...]'"
 
 #: setup.c:388
-#, fuzzy
 msgid "unable to set up work tree using invalid config"
-msgstr "Konnte aktuelles Arbeitsverzeichnis nicht bekommen."
+msgstr "Konnte Arbeitsverzeichnis mit ungültiger Konfiguration nicht einrichten."
 
 #: setup.c:395
 msgid "this operation must be run in a work tree"
-msgstr ""
+msgstr "Diese Operation muss in einem Arbeitsverzeichnis ausgeführt werden."
 
 #: setup.c:506
 #, c-format
 msgid "Expected git repo version <= %d, found %d"
 msgstr "Erwartete Git-Repository-Version <= %d, %d gefunden"
 
 #: setup.c:514
 msgid "unknown repository extensions found:"
 msgstr "Unbekannte Repository-Erweiterungen gefunden:"
 
 #: setup.c:533
-#, fuzzy, c-format
+#, c-format
 msgid "error opening '%s'"
-msgstr "Fehler beim Öffnen von '%s'"
+msgstr "Fehler beim Öffnen von '%s'."
 
 #: setup.c:535
-#, fuzzy, c-format
+#, c-format
 msgid "too large to be a .git file: '%s'"
-msgstr "Konnte Eingabe-Datei '%s' nicht lesen"
+msgstr "Zu groß, um eine .git-Datei zu sein: '%s'"
 
 #: setup.c:537
-#, fuzzy, c-format
+#, c-format
 msgid "error reading %s"
-msgstr "Fehler beim Einpacken von %s."
+msgstr "Fehler beim Lesen von '%s'."
 
 #: setup.c:539
-#, fuzzy, c-format
+#, c-format
 msgid "invalid gitfile format: %s"
-msgstr "Ungültiges Datumsformat: %s"
+msgstr "Ungültiges gitfile-Format: %s"
 
 #: setup.c:541
-#, fuzzy, c-format
+#, c-format
 msgid "no path in gitfile: %s"
-msgstr "Kann Patch-Datei %s nicht öffnen"
+msgstr "Kein Pfad in gitfile: %s"
 
 #: setup.c:543
-#, fuzzy, c-format
+#, c-format
 msgid "not a git repository: %s"
-msgstr "Kein Git-Repository"
+msgstr "Kein Git-Repository: %s"
 
 #: setup.c:642
 #, c-format
 msgid "'$%s' too big"
-msgstr ""
+msgstr "'$%s' zu groß"
 
 #: setup.c:656
-#, fuzzy, c-format
+#, c-format
 msgid "not a git repository: '%s'"
-msgstr "Kein Git-Repository"
+msgstr "Kein Git-Repository: '%s'"
 
 #: setup.c:685 setup.c:687 setup.c:718
-#, fuzzy, c-format
+#, c-format
 msgid "cannot chdir to '%s'"
-msgstr "kann nicht in Verzeichnis %s wechseln"
+msgstr "Kann nicht in Verzeichnis '%s' wechseln."
 
 #: setup.c:690 setup.c:746 setup.c:756 setup.c:795 setup.c:803 setup.c:818
-#, fuzzy
 msgid "cannot come back to cwd"
-msgstr "Kann nicht zurück zum Arbeitsverzeichnis wechseln"
+msgstr "Kann nicht zum aktuellen Arbeitsverzeichnis zurückwechseln."
 
 #: setup.c:816
-#, fuzzy, c-format
+#, c-format
 msgid "not a git repository (or any of the parent directories): %s"
-msgstr "Kein Git-Repository (oder irgendein Elternverzeichnis): %s"
+msgstr "Kein Git-Repository (oder irgendeines der Elternverzeichnisse): %s"
 
 #: setup.c:827
-#, fuzzy, c-format
+#, c-format
 msgid "failed to stat '%*s%s%s'"
-msgstr "Konnte '%s' nicht lesen"
+msgstr "Konnte '%*s%s%s' nicht lesen."
 
 #: setup.c:1057
 msgid "Unable to read current working directory"
 msgstr "Konnte aktuelles Arbeitsverzeichnis nicht lesen."
 
 #: setup.c:1069 setup.c:1075
-#, fuzzy, c-format
+#, c-format
 msgid "cannot change to '%s'"
 msgstr "Kann nicht nach '%s' wechseln."
 
 #: setup.c:1088
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "not a git repository (or any parent up to mount point %s)\n"
 "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
 msgstr ""
 "Kein Git-Repository (oder irgendein Elternverzeichnis bis zum Einhängepunkt "
 "%s)\n"
 "Stoppe bei Dateisystemgrenze (GIT_DISCOVERY_ACROSS_FILESYSTEM nicht gesetzt)."
 
 #: setup.c:1172
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "problem with core.sharedRepository filemode value (0%.3o).\n"
 "The owner of files must always have read and write permissions."
 msgstr ""
 "Problem mit Wert für Dateimodus (0%.3o) von core.sharedRepository.\n"
 "Der Besitzer der Dateien muss immer Lese- und Schreibrechte haben."
 
 #: setup.c:1215
-#, fuzzy
 msgid "open /dev/null or dup failed"
-msgstr "Öffnen von /dev/null fehlgeschlagen"
+msgstr "Öffnen von /dev/null oder dup fehlgeschlagen."
 
 #: setup.c:1230
-#, fuzzy
 msgid "fork failed"
-msgstr "\"fseek\" fehlgeschlagen"
+msgstr "fork fehlgeschlagen"
 
 #: setup.c:1235
-#, fuzzy
 msgid "setsid failed"
-msgstr "\"stash\" fehlgeschlagen"
+msgstr "setsid fehlgeschlagen"
 
 #: sha1_file.c:592
 #, c-format
 msgid "path '%s' does not exist"
 msgstr "Pfad '%s' existiert nicht"
 
@@ -4569,33 +4555,33 @@ msgstr "ungültiges '..' Pfadsegment"
 msgid "failed to read '%s'"
 msgstr "Fehler beim Lesen von '%s'"
 
 #: worktree.c:291
 #, c-format
 msgid "'%s' at main working tree is not the repository directory"
-msgstr ""
+msgstr "'%s' im Hauptarbeitsverzeichnis ist nicht das Repository-Verzeichnis."
 
 #: worktree.c:302
 #, c-format
 msgid "'%s' file does not contain absolute path to the working tree location"
-msgstr ""
+msgstr "'%s' Datei enthält nicht den absoluten Pfad zum Arbeitsverzeichnis."
 
 #: worktree.c:314
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' does not exist"
-msgstr "Pfad '%s' existiert nicht"
+msgstr "'%s' existiert nicht."
 
 #: worktree.c:320
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is not a .git file, error code %d"
-msgstr "'%s' ist nicht gesperrt"
+msgstr "'%s' ist keine .git-Datei, Fehlercode %d"
 
 #: worktree.c:328
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' does not point back to '%s'"
-msgstr "'%s' zeigt auf keinen Commit"
+msgstr "'%s' zeigt nicht zurück auf '%s'"
 
 #: wrapper.c:223 wrapper.c:393
 #, c-format
 msgid "could not open '%s' for reading and writing"
 msgstr "Konnte '%s' nicht zum Lesen und Schreiben öffnen."
 
@@ -5109,13 +5095,13 @@ msgstr "Noch keine Commits in "
 #: wt-status.c:1813
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Branch)"
 
 #: wt-status.c:1844
 msgid "different"
-msgstr ""
+msgstr "unterschiedlich"
 
 #: wt-status.c:1846 wt-status.c:1854
 msgid "behind "
 msgstr "hinterher "
 
 #: wt-status.c:1849 wt-status.c:1852
@@ -5523,12 +5509,14 @@ msgstr "Keine Änderungen -- Patches bereits angewendet."
 msgid "Patch failed at %s %.*s"
 msgstr "Anwendung des Patches fehlgeschlagen bei %s %.*s"
 
 #: builtin/am.c:1838
 msgid "Use 'git am --show-current-patch' to see the failed patch"
 msgstr ""
+"Benutzen Sie 'git am --show-current-patch', um den\n"
+"fehlgeschlagenen Patch zu sehen."
 
 #: builtin/am.c:1882
 msgid ""
 "No changes - did you forget to use 'git add'?\n"
 "If there is nothing left to stage, chances are that something else\n"
 "already introduced the same changes; you might want to skip this patch."
@@ -5674,18 +5662,17 @@ msgstr "den aktuellen Patch auslassen"
 msgid "restore the original branch and abort the patching operation."
 msgstr ""
 "ursprünglichen Branch wiederherstellen und Anwendung der Patches abbrechen"
 
 #: builtin/am.c:2287
 msgid "abort the patching operation but keep HEAD where it is."
-msgstr ""
+msgstr "Patch-Operation abbrechen, aber HEAD an aktueller Stelle belassen"
 
 #: builtin/am.c:2290
-#, fuzzy
 msgid "show the patch being applied."
-msgstr "Keine Änderungen -- Patches bereits angewendet."
+msgstr "den Patch, der gerade angewendet wird, anzeigen"
 
 #: builtin/am.c:2294
 msgid "lie about committer date"
 msgstr "Autor-Datum als Commit-Datum verwenden"
 
 #: builtin/am.c:2296
@@ -5750,15 +5737,14 @@ msgstr "Konnte Ausgabe nicht umleiten."
 
 #: builtin/archive.c:37
 msgid "git archive: Remote with no URL"
 msgstr "git archive: Externes Archiv ohne URL"
 
 #: builtin/archive.c:58
-#, fuzzy
 msgid "git archive: expected ACK/NAK, got a flush packet"
-msgstr "git archive: habe ACK/NAK erwartet, aber EOF bekommen"
+msgstr "git archive: ACK/NAK erwartet, Flush-Paket bekommen"
 
 #: builtin/archive.c:61
 #, c-format
 msgid "git archive: NACK %s"
 msgstr "git archive: NACK %s"
 
@@ -7434,17 +7420,14 @@ msgstr ""
 msgid "--shallow-exclude is ignored in local clones; use file:// instead."
 msgstr ""
 "--shallow-exclude wird in lokalen Klonen ignoriert; benutzen Sie stattdessen "
 "file://"
 
 #: builtin/clone.c:1099
-#, fuzzy
 msgid "--filter is ignored in local clones; use file:// instead."
-msgstr ""
-"Die Option --depth wird in lokalen Klonen ignoriert; benutzen Sie "
-"stattdessen file://"
+msgstr "--filter wird in lokalen Klonen ignoriert; benutzen Sie stattdessen file://"
 
 #: builtin/clone.c:1102
 msgid "source repository is shallow, ignoring --local"
 msgstr ""
 "Quelle ist ein Repository mit unvollständiger Historie (shallow),\n"
 "ignoriere --local"
@@ -7769,15 +7752,14 @@ msgstr ""
 
 #: builtin/commit.c:1112
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "Es kann nur eine Option von -c/-C/-F/--fixup verwendet werden."
 
 #: builtin/commit.c:1114
-#, fuzzy
 msgid "Option -m cannot be combined with -c/-C/-F."
-msgstr "Die Option -m kann nicht mit -c/-C/-F/--fixup kombiniert werden."
+msgstr "Die Option -m kann nicht mit -c/-C/-F kombiniert werden."
 
 #: builtin/commit.c:1122
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr ""
 "Die Option --reset--author kann nur mit -C, -c oder --amend verwendet werden."
 
@@ -7813,13 +7795,13 @@ msgstr "Branchinformationen anzeigen"
 #: builtin/commit.c:1282
 msgid "show stash information"
 msgstr "Stashinformationen anzeigen"
 
 #: builtin/commit.c:1284 builtin/commit.c:1447
 msgid "compute full ahead/behind values"
-msgstr ""
+msgstr "voraus/hinterher-Werte berechnen"
 
 #: builtin/commit.c:1286
 msgid "version"
 msgstr "Version"
 
 #: builtin/commit.c:1286 builtin/commit.c:1449 builtin/push.c:542
@@ -8656,13 +8638,13 @@ msgid "prune remote-tracking branches no longer on remote"
 msgstr ""
 "Remote-Tracking-Branches entfernen, die sich nicht mehr im Remote-Repository "
 "befinden"
 
 #: builtin/fetch.c:141
 msgid "prune local tags no longer on remote and clobber changed tags"
-msgstr ""
+msgstr "lokale Tags entfernen, die sich nicht mehr im Remote-Repository befinden, und geänderte Tags aktualisieren"
 
 #: builtin/fetch.c:142 builtin/fetch.c:165 builtin/pull.c:126
 msgid "on-demand"
 msgstr "bei-Bedarf"
 
 #: builtin/fetch.c:143
@@ -8848,12 +8830,14 @@ msgid "Could not fetch %s"
 msgstr "Konnte nicht von %s anfordern"
 
 #: builtin/fetch.c:1325 builtin/fetch.c:1498
 msgid ""
 "--filter can only be used with the remote configured in core.partialClone"
 msgstr ""
+"--filter kann nur mit den Remote-Repositories verwendet werden,\n"
+"die in core.partialClone konfiguriert sind."
 
 #: builtin/fetch.c:1350
 msgid ""
 "No remote repository specified.  Please, specify either a URL or a\n"
 "remote name from which new revisions should be fetched."
 msgstr ""
@@ -9793,20 +9777,20 @@ msgstr "lokales Objekt %s ist beschädigt"
 #: builtin/index-pack.c:1397
 #, c-format
 msgid "packfile name '%s' does not end with '.pack'"
 msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'"
 
 #: builtin/index-pack.c:1422
-#, fuzzy, c-format
+#, c-format
 msgid "cannot write %s file '%s'"
-msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben"
+msgstr "Kann %s Datei '%s' nicht schreiben."
 
 #: builtin/index-pack.c:1430
-#, fuzzy, c-format
+#, c-format
 msgid "cannot close written %s file '%s'"
-msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen"
+msgstr "Kann eben geschriebene %s Datei '%s' nicht schließen."
 
 #: builtin/index-pack.c:1454
 msgid "error while closing pack file"
 msgstr "Fehler beim Schließen der Paketdatei"
 
 #: builtin/index-pack.c:1468
@@ -11884,13 +11868,13 @@ msgstr "Bitmap-Index zusammen mit Pack-Index schreiben"
 #: builtin/pack-objects.c:3036
 msgid "handling for missing objects"
 msgstr "Behandlung für fehlende Objekte"
 
 #: builtin/pack-objects.c:3039
 msgid "do not pack objects in promisor packfiles"
-msgstr ""
+msgstr "keine Objekte aus Packdateien von partiell geklonten Remote-Repositories packen"
 
 #: builtin/pack-objects.c:3178
 msgid "Counting objects"
 msgstr "Zähle Objekte"
 
 #: builtin/pack-refs.c:6
@@ -11924,13 +11908,13 @@ msgstr "gelöschte Objekte melden"
 #: builtin/prune.c:110
 msgid "expire objects older than <time>"
 msgstr "Objekte älter als <Zeit> verfallen lassen"
 
 #: builtin/prune.c:112
 msgid "limit traversal to objects outside promisor packfiles"
-msgstr ""
+msgstr "Traversierung auf Objekte außerhalb von Packdateien aus partiell geklonten Remote-Repositories einschränken"
 
 #: builtin/prune.c:126
 msgid "cannot prune in a precious-objects repo"
 msgstr "kann \"prune\" in precious-objects Repository nicht ausführen"
 
 #: builtin/pull.c:54 builtin/pull.c:56
@@ -13464,16 +13448,14 @@ msgstr "Konnte Index-Datei nicht zu Commit '%s' setzen."
 
 #: builtin/reset.c:390
 msgid "Could not write new index file."
 msgstr "Konnte neue Index-Datei nicht schreiben."
 
 #: builtin/rev-list.c:397
-#, fuzzy
 msgid "cannot combine --exclude-promisor-objects and --missing"
-msgstr ""
-"--use-bitmap-index kann nicht mit dem Filtern von Objekten kombiniert werden."
+msgstr "--exclude-promisor-objects und --missing können nicht kombiniert werden."
 
 #: builtin/rev-list.c:455
 msgid "object filtering requires --objects"
 msgstr "Das Filtern von Objekten erfordert --objects."
 
 #: builtin/rev-list.c:458
@@ -13955,13 +13937,13 @@ msgstr "Referenz nicht gefunden: %s"
 #, c-format
 msgid "Expecting a full ref name, got %s"
 msgstr "Vollständiger Referenzname erwartet, %s erhalten"
 
 #: builtin/submodule--helper.c:59
 msgid "submodule--helper print-default-remote takes no arguments"
-msgstr ""
+msgstr "'submodule--helper print-default-remote' erwartet keine Argumente."
 
 #: builtin/submodule--helper.c:96
 #, c-format
 msgid "cannot strip one component off url '%s'"
 msgstr "Kann eine Komponente von URL '%s' nicht extrahieren"
 
@@ -14055,108 +14037,94 @@ msgstr "git submodule status [--quiet] [--cached] [--recursive] [<Pfad>...]"
 
 #: builtin/submodule--helper.c:742
 msgid "git submodule--helper name <path>"
 msgstr "git submodule--helper name <Pfad>"
 
 #: builtin/submodule--helper.c:806
-#, fuzzy, c-format
+#, c-format
 msgid "Synchronizing submodule url for '%s'\n"
-msgstr "Synchronisiere Submodul-URL für '$displaypath'"
+msgstr "Synchronisiere Submodul-URL für '%s'\n"
 
 #: builtin/submodule--helper.c:812
-#, fuzzy, c-format
+#, c-format
 msgid "failed to register url for submodule path '%s'"
-msgstr ""
-"Fehler beim Eintragen der URL für Submodul-Pfad '%s' in die Konfiguration."
+msgstr "Fehler beim Registrieren der URL für Submodul-Pfad '%s'."
 
 #: builtin/submodule--helper.c:826
-#, fuzzy, c-format
+#, c-format
 msgid "failed to get the default remote for submodule '%s'"
-msgstr ""
-"Fehler bei Änderung des Aktualisierungsmodus für Submodul-Pfad '%s' in der\n"
-"Konfiguration."
+msgstr "Fehler beim Lesen des Standard-Remote-Repositories für Submodul '%s'."
 
 #: builtin/submodule--helper.c:837
-#, fuzzy, c-format
+#, c-format
 msgid "failed to update remote for submodule '%s'"
-msgstr ""
-"Fehler bei Änderung des Aktualisierungsmodus für Submodul-Pfad '%s' in der\n"
-"Konfiguration."
+msgstr "Fehler beim Aktualisieren des Remote-Repositories für Submodul '%s'."
 
 #: builtin/submodule--helper.c:885
-#, fuzzy
 msgid "Suppress output of synchronizing submodule url"
-msgstr "Ausgaben bei Initialisierung eines Submoduls unterdrücken"
+msgstr "Ausgaben bei der Synchronisierung der Submodul-URLs unterdrücken"
 
 #: builtin/submodule--helper.c:887
-#, fuzzy
 msgid "Recurse into nested submodules"
 msgstr "Rekursion in verschachtelte Submodule durchführen"
 
 #: builtin/submodule--helper.c:892
-#, fuzzy
 msgid "git submodule--helper sync [--quiet] [--recursive] [<path>]"
-msgstr "git submodule status [--quiet] [--cached] [--recursive] [<Pfad>...]"
+msgstr "git submodule--helper sync [--quiet] [--recursive] [<Pfad>]"
 
 #: builtin/submodule--helper.c:946
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Submodule work tree '%s' contains a .git directory (use 'rm -rf' if you "
 "really want to remove it including all of its history)"
 msgstr ""
-"Arbeitsverzeichnis von Submodul in '$displaypath' enthält ein .git-"
-"Verzeichnis\n"
-"(benutzen Sie 'rm -rf' wenn Sie dieses wirklich mitsamt seiner Historie "
-"löschen\n"
-"möchten)"
+"Arbeitsverzeichnis von Submodul in '%s' enthält ein .git-Verzeichnis\n"
+"(benutzen Sie 'rm -rf', wenn Sie dieses wirklich mitsamt seiner Historie\n"
+"löschen möchten)"
 
 #: builtin/submodule--helper.c:958
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Submodule work tree '%s' contains local modifications; use '-f' to discard "
 "them"
 msgstr ""
-"Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Änderungen; "
-"verwenden Sie '-f', um diese zu verwerfen"
+"Arbeitsverzeichnis von Submodul in '%s' enthält lokale Änderungen;\n"
+"verwenden Sie '-f', um diese zu verwerfen."
 
 #: builtin/submodule--helper.c:966
-#, fuzzy, c-format
+#, c-format
 msgid "Cleared directory '%s'\n"
-msgstr "Verzeichnis '$displaypath' bereinigt."
+msgstr "Verzeichnis '%s' bereinigt.\n"
 
 #: builtin/submodule--helper.c:968
-#, fuzzy, c-format
+#, c-format
 msgid "Could not remove submodule work tree '%s'\n"
-msgstr ""
-"Konnte Arbeitsverzeichnis des Submoduls in '$displaypath' nicht löschen."
+msgstr "Konnte Arbeitsverzeichnis des Submoduls in '%s' nicht löschen.\n"
 
 #: builtin/submodule--helper.c:977
-#, fuzzy, c-format
+#, c-format
 msgid "could not create empty submodule directory %s"
-msgstr ""
-"Konnte kein leeres Verzeichnis für Submodul in '$displaypath' erstellen."
+msgstr "Konnte kein leeres Verzeichnis für Submodul in '%s' erstellen."
 
 #: builtin/submodule--helper.c:993
-#, fuzzy, c-format
+#, c-format
 msgid "Submodule '%s' (%s) unregistered for path '%s'\n"
-msgstr "Submodul '%s' (%s) für Pfad '%s' in die Konfiguration eingetragen.\n"
+msgstr "Submodul '%s' (%s) für Pfad '%s' ausgetragen.\n"
 
 #: builtin/submodule--helper.c:1022
 msgid "Remove submodule working trees even if they contain local changes"
-msgstr ""
+msgstr "Arbeitsverzeichnisse von Submodulen löschen, auch wenn lokale Änderungen vorliegen"
 
 #: builtin/submodule--helper.c:1023
-#, fuzzy
 msgid "Unregister all submodules"
-msgstr "Rekursion in Submodule durchführen"
+msgstr "alle Submodule austragen"
 
 #: builtin/submodule--helper.c:1028
-#, fuzzy
 msgid ""
 "git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"
-msgstr "git submodule status [--quiet] [--cached] [--recursive] [<Pfad>...]"
+msgstr "git submodule deinit [--quiet] [-f | --force] [--all | [--] [<Pfad>...]]"
 
 #: builtin/submodule--helper.c:1042
 msgid "Use '--all' if you really want to deinitialize all submodules"
 msgstr ""
 "Verwenden Sie '--all', wenn Sie wirklich alle Submodule deinitialisieren\n"
 "möchten."
@@ -14453,15 +14421,14 @@ msgstr "annotiertes Tag, benötigt eine Beschreibung"
 
 #: builtin/tag.c:392
 msgid "tag message"
 msgstr "Tag-Beschreibung"
 
 #: builtin/tag.c:394
-#, fuzzy
 msgid "force edit of tag message"
-msgstr "Bearbeitung des Commits erzwingen"
+msgstr "Bearbeitung der Tag-Beschreibung erzwingen"
 
 #: builtin/tag.c:395
 msgid "annotated and GPG-signed tag"
 msgstr "annotiertes und GPG-signiertes Tag"
 
 #: builtin/tag.c:399
@@ -14900,37 +14867,34 @@ msgstr "git verify-tag [-v | --verbose] [--format=<Format>] <Tag>..."
 
 #: builtin/verify-tag.c:37
 msgid "print tag contents"
 msgstr "Tag-Inhalte ausgeben"
 
 #: builtin/worktree.c:17
-#, fuzzy
 msgid "git worktree add [<options>] <path> [<commit-ish>]"
-msgstr "git worktree add [<Optionen>] <Pfad> [<Branch>]"
+msgstr "git worktree add [<Optionen>] <Pfad> [<Commit-Angabe>]"
 
 #: builtin/worktree.c:18
 msgid "git worktree list [<options>]"
 msgstr "git worktree list [<Optionen>]"
 
 #: builtin/worktree.c:19
 msgid "git worktree lock [<options>] <path>"
 msgstr "git worktree lock [<Optionen>] <Pfad>"
 
 #: builtin/worktree.c:20
-#, fuzzy
 msgid "git worktree move <worktree> <new-path>"
-msgstr "git worktree lock [<Optionen>] <Pfad>"
+msgstr "git worktree move <Arbeitsverzeichnis> <neuer-Pfad>"
 
 #: builtin/worktree.c:21
 msgid "git worktree prune [<options>]"
 msgstr "git worktree prune [<Optionen>]"
 
 #: builtin/worktree.c:22
-#, fuzzy
 msgid "git worktree remove [<options>] <worktree>"
-msgstr "git worktree lock [<Optionen>] <Pfad>"
+msgstr "git worktree remove [<Optionen>] <Arbeitsverzeichnis>"
 
 #: builtin/worktree.c:23
 msgid "git worktree unlock <path>"
 msgstr "git worktree unlock <Pfad>"
 
 #: builtin/worktree.c:60
@@ -15060,87 +15024,86 @@ msgstr "'%s' ist bereits gesperrt"
 msgid "'%s' is not locked"
 msgstr "'%s' ist nicht gesperrt"
 
 #: builtin/worktree.c:645
 msgid "working trees containing submodules cannot be moved or removed"
 msgstr ""
+"Arbeitsverzeichnisse, die Submodule enthalten, können nicht verschoben oder\n"
+"entfernt werden."
 
 #: builtin/worktree.c:672 builtin/worktree.c:811
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is a main working tree"
-msgstr "'%s' ist kein Arbeitsverzeichnis"
+msgstr "'%s' ist ein Hauptarbeitsverzeichnis"
 
 #: builtin/worktree.c:677
-#, fuzzy, c-format
+#, c-format
 msgid "could not figure out destination name from '%s'"
-msgstr "Konnte Git-Verzeichnis nicht von '%s' nach '%s' migrieren."
+msgstr "Konnte Zielname aus '%s' nicht bestimmen."
 
 #: builtin/worktree.c:683
-#, fuzzy, c-format
+#, c-format
 msgid "target '%s' already exists"
-msgstr "Tag '%s' existiert bereits"
+msgstr "Ziel '%s' existiert bereits."
 
 #: builtin/worktree.c:690
-#, fuzzy, c-format
+#, c-format
 msgid "cannot move a locked working tree, lock reason: %s"
-msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
+msgstr "Kann gesperrtes Arbeitsverzeichnis nicht verschieben, Sperrgrund: %s"
 
 #: builtin/worktree.c:692
-#, fuzzy
 msgid "cannot move a locked working tree"
-msgstr "Kann Zustand des Arbeitsverzeichnisses nicht aufzeichnen"
+msgstr "Kann gesperrtes Arbeitsverzeichnisses nicht verschieben."
 
 #: builtin/worktree.c:695
 #, c-format
 msgid "validation failed, cannot move working tree: %s"
-msgstr ""
+msgstr "Validierung fehlgeschlagen, kann Arbeitszeichnis nicht verschieben: %s"
 
 #: builtin/worktree.c:700
-#, fuzzy, c-format
+#, c-format
 msgid "failed to move '%s' to '%s'"
-msgstr "Fehler beim Öffnen von '%s': %s"
+msgstr "Fehler beim Verschieben von '%s' nach '%s'"
 
 #: builtin/worktree.c:748
-#, fuzzy, c-format
+#, c-format
 msgid "failed to run 'git status' on '%s'"
-msgstr "Fehler beim Schreiben nach '%s'"
+msgstr "Fehler beim Ausführen von 'git status' auf '%s'"
 
 #: builtin/worktree.c:752
 #, c-format
 msgid "'%s' is dirty, use --force to delete it"
-msgstr ""
+msgstr "'%s' ist verändert, benutzen Sie --force zum Löschen"
 
 #: builtin/worktree.c:757
-#, fuzzy, c-format
+#, c-format
 msgid "failed to run 'git status' on '%s', code %d"
-msgstr "Konnte 'git status' in Submodul '%s' nicht ausführen."
+msgstr "Fehler beim Ausführen von 'git status' auf '%s'. Code: %d"
 
 #: builtin/worktree.c:768 builtin/worktree.c:782
-#, fuzzy, c-format
+#, c-format
 msgid "failed to delete '%s'"
-msgstr "Fehler beim Ausführen von '%s'"
+msgstr "Fehler beim Löschen von '%s'"
 
 #: builtin/worktree.c:794
-#, fuzzy
 msgid "force removing even if the worktree is dirty"
-msgstr "Verschieben/Umbenennen erzwingen, auch wenn das Ziel existiert"
+msgstr "Löschen erzwingen, auch wenn das Arbeitsverzeichnis geändert wurde"
 
 #: builtin/worktree.c:815
-#, fuzzy, c-format
+#, c-format
 msgid "cannot remove a locked working tree, lock reason: %s"
-msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
+msgstr "Kann gesperrtes Arbeitsverzeichnis nicht löschen, Sperrgrund: %s"
 
 #: builtin/worktree.c:817
-#, fuzzy
 msgid "cannot remove a locked working tree"
-msgstr "Kann Zustand des Arbeitsverzeichnisses nicht aufzeichnen"
+msgstr "Kann gesperrtes Arbeitsverzeichnis nicht löschen."
 
 #: builtin/worktree.c:820
 #, c-format
 msgid "validation failed, cannot remove working tree: %s"
-msgstr ""
+msgstr "Validierung fehlgeschlagen, kann Arbeitsverzeichnis nicht löschen: %s"
 
 #: builtin/write-tree.c:14
 msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
 msgstr "git write-tree [--missing-ok] [--prefix=<Präfix>/]"
 
 #: builtin/write-tree.c:27
@@ -15202,12 +15165,17 @@ msgid ""
 "git [--version] [--help] [-C <path>] [-c <name>=<value>]\n"
 "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 "           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
 "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
 "           <command> [<args>]"
 msgstr ""
+"git [--version] [--help] [-C <Pfad>] [-c <Name>=<Wert>]\n"
+"           [--exec-path[=<Pfad>]] [--html-path] [--man-path] [--info-path]\n"
+"           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
+"           [--git-dir=<Pfad>] [--work-tree=<Pfad>] [--namespace=<Name>]\n"
+"           <Befehl> [<Argumente>]"
 
 #: git.c:15
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
 "concept guides. See 'git help <command>' or 'git help <concept>'\n"
 "to read about a specific subcommand or concept."
@@ -15217,53 +15185,53 @@ msgstr ""
 "oder 'git help <Konzept>', um mehr über einen spezifischen Befehl oder\n"
 "Konzept zu erfahren."
 
 #: git.c:95
 #, c-format
 msgid "no directory given for --git-dir\n"
-msgstr ""
+msgstr "Kein Verzeichnis für --git-dir angegeben.\n"
 
 #: git.c:109
 #, c-format
 msgid "no namespace given for --namespace\n"
-msgstr ""
+msgstr "Kein Namespace für --namespace angegeben.\n"
 
 #: git.c:123
 #, c-format
 msgid "no directory given for --work-tree\n"
-msgstr ""
+msgstr "Kein Verzeichnis für --work-tree angegeben.\n"
 
 #: git.c:137
-#, fuzzy, c-format
+#, c-format
 msgid "no prefix given for --super-prefix\n"
-msgstr "%s unterstützt kein --super-prefix"
+msgstr "Kein Präfix für --super-prefix angegeben.\n"
 
 #: git.c:159
 #, c-format
 msgid "-c expects a configuration string\n"
-msgstr ""
+msgstr "-c erwartet einen Konfigurationsstring.\n"
 
 #: git.c:197
 #, c-format
 msgid "no directory given for -C\n"
-msgstr ""
+msgstr "Kein Verzeichnis für -C angegeben.\n"
 
 #: git.c:212
-#, fuzzy, c-format
+#, c-format
 msgid "unknown option: %s\n"
-msgstr "unbekannte Option: %s"
+msgstr "Unbekannte Option: %s\n"
 
 #: git.c:687
 #, c-format
 msgid "expansion of alias '%s' failed; '%s' is not a git command\n"
-msgstr ""
+msgstr "Erweiterung von Alias '%s' fehlgeschlagen; '%s' ist kein Git-Befehl.\n"
 
 #: git.c:699
-#, fuzzy, c-format
+#, c-format
 msgid "failed to run command '%s': %s\n"
-msgstr "Fehler beim Öffnen von '%s': %s"
+msgstr "Fehler beim Ausführen von Befehl '%s': %s\n"
 
 #: http.c:342
 #, c-format
 msgid "negative value for http.postbuffer; defaulting to %d"
 msgstr "negativer Wert für http.postbuffer; benutze Standardwert %d"
 
@@ -15958,13 +15926,13 @@ msgstr ""
 "Der Stash-Eintrag wird für den Fall behalten, dass Sie diesen nochmal "
 "benötigen."
 
 #: git-stash.sh:656
 #, sh-format
 msgid "Dropped ${REV} ($s)"
-msgstr "Gelöscht ${REV} ($s)"
+msgstr "${REV} ($s) gelöscht"
 
 #: git-stash.sh:657
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen"
 
@@ -16948,126 +16916,119 @@ msgstr "Keine Änderungen.\n"
 
 #: git-add--interactive.perl:1331
 msgid "Patch update"
 msgstr "Patch Aktualisierung"
 
 #: git-add--interactive.perl:1383
-#, fuzzy, perl-format
+#, perl-format
 msgid "Stage mode change [y,n,q,a,d%s,?]? "
-msgstr "Modusänderung der Staging-Area hinzufügen [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1384
-#, fuzzy, perl-format
+#, perl-format
 msgid "Stage deletion [y,n,q,a,d%s,?]? "
-msgstr "Löschung der Staging-Area hinzufügen [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1385
-#, fuzzy, perl-format
+#, perl-format
 msgid "Stage this hunk [y,n,q,a,d%s,?]? "
-msgstr "Diesen Patch-Block der Staging-Area hinzufügen [y,n,q,a,d,/%s,?]? "
+msgstr "Diesen Patch-Block der Staging-Area hinzufügen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1388
-#, fuzzy, perl-format
+#, perl-format
 msgid "Stash mode change [y,n,q,a,d%s,?]? "
-msgstr "Modusänderung stashen [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung stashen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1389
-#, fuzzy, perl-format
+#, perl-format
 msgid "Stash deletion [y,n,q,a,d%s,?]? "
-msgstr "Löschung stashen [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung stashen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1390
-#, fuzzy, perl-format
+#, perl-format
 msgid "Stash this hunk [y,n,q,a,d%s,?]? "
-msgstr "Diesen Patch-Block stashen [y,n,q,a,d,/%s,?]? "
+msgstr "Diesen Patch-Block stashen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1393
-#, fuzzy, perl-format
+#, perl-format
 msgid "Unstage mode change [y,n,q,a,d%s,?]? "
-msgstr "Modusänderung aus der Staging-Area entfernen [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1394
-#, fuzzy, perl-format
+#, perl-format
 msgid "Unstage deletion [y,n,q,a,d%s,?]? "
-msgstr "Löschung aus der Staging-Area entfernen [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1395
-#, fuzzy, perl-format
+#, perl-format
 msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
-msgstr "Diesen Patch-Block aus der Staging-Area entfernen [y,n,q,a,d,/%s,?]? "
+msgstr "Diesen Patch-Block aus der Staging-Area entfernen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1398
-#, fuzzy, perl-format
+#, perl-format
 msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
-msgstr "Modusänderung auf Index anwenden [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung auf Index anwenden [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1399
-#, fuzzy, perl-format
+#, perl-format
 msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
-msgstr "Löschung auf Index anwenden [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung auf Index anwenden [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1400
-#, fuzzy, perl-format
+#, perl-format
 msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
-msgstr "Diesen Patch-Block auf Index anwenden [y,n,q,a,d,/%s,?]? "
+msgstr "Diesen Patch-Block auf Index anwenden [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1403
-#, fuzzy, perl-format
+#, perl-format
 msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
-msgstr "Modusänderung im Arbeitsverzeichnis verwerfen [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1404
-#, fuzzy, perl-format
+#, perl-format
 msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
-msgstr "Löschung im Arbeitsverzeichnis verwerfen [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1405
-#, fuzzy, perl-format
+#, perl-format
 msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
-msgstr "diesen Patch-Block im Arbeitsverzeichnis verwerfen [y,n,q,a,d,/%s,?]? "
+msgstr "diesen Patch-Block im Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1408
-#, fuzzy, perl-format
+#, perl-format
 msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Modusänderung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1409
-#, fuzzy, perl-format
+#, perl-format
 msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Löschung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1410
-#, fuzzy, perl-format
+#, perl-format
 msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d,/"
-"%s,?]? "
+msgstr "Diesen Patch-Block vom Index und Arbeitsverzeichnis verwerfen [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1413
-#, fuzzy, perl-format
+#, perl-format
 msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Modusänderung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d,/%s,?]? "
+msgstr "Modusänderung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1414
-#, fuzzy, perl-format
+#, perl-format
 msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
-msgstr "Löschung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d,/%s,?]? "
+msgstr "Löschung auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1415
-#, fuzzy, perl-format
+#, perl-format
 msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
-msgstr ""
-"Diesen Patch-Block auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d,/"
-"%s,?]? "
+msgstr "Diesen Patch-Block auf Index und Arbeitsverzeichnis anwenden [y,n,q,a,d%s,?]? "
 
 #: git-add--interactive.perl:1515
 msgid "No other hunks to goto\n"
-msgstr ""
+msgstr "Keine anderen Patch-Blöcke verbleibend\n"
 
 #: git-add--interactive.perl:1522
 msgid "go to which hunk (<ret> to see more)? "
 msgstr "zu welchem Patch-Block springen (<Enter> für mehr Informationen)? "
 
 #: git-add--interactive.perl:1524
@@ -17085,13 +17046,13 @@ msgid "Sorry, only %d hunk available.\n"
 msgid_plural "Sorry, only %d hunks available.\n"
 msgstr[0] "Entschuldigung, nur %d Patch-Block verfügbar.\n"
 msgstr[1] "Entschuldigung, nur %d Patch-Blöcke verfügbar.\n"
 
 #: git-add--interactive.perl:1564
 msgid "No other hunks to search\n"
-msgstr ""
+msgstr "Keine anderen Patch-Blöcke zum Durchsuchen\n"
 
 #: git-add--interactive.perl:1568
 msgid "search for regex? "
 msgstr "Suche nach regulärem Ausdruck? "
 
 #: git-add--interactive.perl:1581
@@ -17110,24 +17071,24 @@ msgstr "Kein vorheriger Patch-Block\n"
 #: git-add--interactive.perl:1612 git-add--interactive.perl:1631
 msgid "No next hunk\n"
 msgstr "Kein folgender Patch-Block\n"
 
 #: git-add--interactive.perl:1637
 msgid "Sorry, cannot split this hunk\n"
-msgstr ""
+msgstr "Entschuldigung, kann diesen Patch-Block nicht aufteilen.\n"
 
 #: git-add--interactive.perl:1643
 #, perl-format
 msgid "Split into %d hunk.\n"
 msgid_plural "Split into %d hunks.\n"
 msgstr[0] "In %d Patch-Block aufgeteilt.\n"
 msgstr[1] "In %d Patch-Blöcke aufgeteilt.\n"
 
 #: git-add--interactive.perl:1653
 msgid "Sorry, cannot edit this hunk\n"
-msgstr ""
+msgstr "Entschuldigung, kann diesen Patch-Block nicht bearbeiten.\n"
 
 #: git-add--interactive.perl:1699
 msgid "Review diff"
 msgstr "Diff überprüfen"
 
 #. TRANSLATORS: please do not translate the command names
@@ -17203,12 +17164,14 @@ msgstr ""
 
 #: git-send-email.perl:386
 msgid ""
 "`batch-size` and `relogin` must be specified together (via command-line or "
 "configuration option)\n"
 msgstr ""
+"'batch-size' und 'relogin' müssen gemeinsam angegeben werden (über Kommandozeile\n"
+"oder Konfigurationsoption)\n"
 
 #: git-send-email.perl:456
 #, perl-format
 msgid "Unknown --suppress-cc field: '%s'\n"
 msgstr "Unbekanntes --suppress-cc Feld: '%s'\n"
 
-- 
2.16.2.395.g2e18187df


^ permalink raw reply related	[relevance 1%]

* Re: [PATCH v5 5/6] worktree: teach "add" to check out existing branches
  2018-03-25 13:49 21%         ` [PATCH v5 5/6] " Thomas Gummerer
@ 2018-03-27  9:04  7%           ` Eric Sunshine
  2018-03-30 14:04  0%             ` Thomas Gummerer
  0 siblings, 1 reply; 200+ results
From: Eric Sunshine @ 2018-03-27  9:04 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: Git List, Nguyễn Thái Ngọc Duy, Junio C Hamano

On Sun, Mar 25, 2018 at 9:49 AM, Thomas Gummerer <t.gummerer@gmail.com> wrote:
> Currently 'git worktree add <path>' creates a new branch named after the
> basename of the path by default.  If a branch with that name already
> exists, the command refuses to do anything, unless the '--force' option
> is given.
>
> However we can do a little better than that, and check the branch out if
> it is not checked out anywhere else.  This will help users who just want
> to check an existing branch out into a new worktree, and save a few
> keystrokes.
> [...]
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> @@ -317,7 +318,10 @@ static int add_worktree(const char *path, const char *refname,
> -       if (opts->new_branch)
> +       if (opts->checkout_existing_branch)
> +               fprintf_ln(stderr, _("checking out branch '%s'"),
> +                          refname);

This fprintf_ln() can easily fit on one line; no need to wrap
'refname' to the next one.

Not worth a re-roll, though.

> +       else if (opts->new_branch)
>                 fprintf_ln(stderr, _("creating branch '%s'"), opts->new_branch);
> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> @@ -198,13 +198,26 @@ test_expect_success '"add" with <branch> omitted' '
> -test_expect_success '"add" auto-vivify does not clobber existing branch' '
> +test_expect_success '"add" checks out existing branch of dwimd name' '
>         test_commit c1 &&
>         test_commit c2 &&
>         git branch precious HEAD~1 &&
> -       test_must_fail git worktree add precious &&
> +       git worktree add precious &&
>         test_cmp_rev HEAD~1 precious &&
> -       test_path_is_missing precious
> +       (
> +               cd precious &&
> +               test_cmp_rev precious HEAD
> +       )
> +'

Looking at this more closely, once it stops being a "don't clobber
precious branch" test, it's doing more than it needs to do, thus is
confusing for future readers. The setup -- creating two commits and
making "precious" point one commit back -- was very intentional and
allowed the test to verify not only that the worktree wasn't created
but that "precious" didn't change to reference a different commit.
However, _none_ of this matters once it becomes a dwim'ing test; the
unnecessary code is confusing since it doesn't make sense in the
context of dwim'ing. I _think_ the entire test can collapse to:

    git branch existing &&
    git worktree add existing &&
    (
        cd existing &&
        test_cmp_rev existing HEAD
    )

In other words, this patch should drop the "precious" test altogether
and just introduce a new dwim'ing test (and drop patch 6/6).

I do think that with the potential confusion to future readers, this
does deserve a re-roll.

> +test_expect_success '"add" auto-vivify fails with checked out branch' '
> +       git checkout -b test-branch &&
> +       test_must_fail git worktree add test-branch &&
> +       test_path_is_missing test-branch
> +'
> +
> +test_expect_success '"add --force" with existing dwimd name doesnt die' '
> +       git worktree add --force test-branch
>  '

^ permalink raw reply	[relevance 7%]

* [PATCH v5 6/6] t2025: rename now outdated branch name
  2018-03-25 13:49  9%       ` [PATCH v5 0/6] " Thomas Gummerer
  2018-03-25 13:49 21%         ` [PATCH v5 5/6] " Thomas Gummerer
@ 2018-03-25 13:49 17%         ` Thomas Gummerer
    2 siblings, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-03-25 13:49 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Before the previous commit, the branch named precious was used to check
that 'git worktree' wouldn't clobber the branch.  While 'git worktree'
still shouldn't (and doesn't) modify the branch, that's no longer the
main thing the test is checking.

Rename the branch to avoid making future readers wonder why this
particular branch is more "precious" than others.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 t/t2025-worktree-add.sh | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index ae602cf20e..fb99f4c46f 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -201,12 +201,12 @@ test_expect_success '"add" with <branch> omitted' '
 test_expect_success '"add" checks out existing branch of dwimd name' '
 	test_commit c1 &&
 	test_commit c2 &&
-	git branch precious HEAD~1 &&
-	git worktree add precious &&
-	test_cmp_rev HEAD~1 precious &&
+	git branch dwim HEAD~1 &&
+	git worktree add dwim &&
+	test_cmp_rev HEAD~1 dwim &&
 	(
-		cd precious &&
-		test_cmp_rev precious HEAD
+		cd dwim &&
+		test_cmp_rev dwim HEAD
 	)
 '
 
-- 
2.16.1.77.g8685934aa2


^ permalink raw reply related	[relevance 17%]

* [PATCH v5 5/6] worktree: teach "add" to check out existing branches
  2018-03-25 13:49  9%       ` [PATCH v5 0/6] " Thomas Gummerer
@ 2018-03-25 13:49 21%         ` Thomas Gummerer
  2018-03-27  9:04  7%           ` Eric Sunshine
  2018-03-25 13:49 17%         ` [PATCH v5 6/6] t2025: rename now outdated branch name Thomas Gummerer
    2 siblings, 1 reply; 200+ results
From: Thomas Gummerer @ 2018-03-25 13:49 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 19 +++++++++++++++++--
 t/t2025-worktree-add.sh        | 19 ++++++++++++++++---
 3 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..eaa6bf713f 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, a worktree with a branch named after
+`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` exists in the repository,
+it will be checked out in the new worktree, if it's not checked out
+anywhere else, otherwise the command will refuse to create the
+worktree (unless `--force` is used).
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index c296c3eacb..895838b943 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -28,6 +28,7 @@ struct add_opts {
 	int checkout;
 	int keep_locked;
 	const char *new_branch;
+	int checkout_existing_branch;
 };
 
 static int show_only;
@@ -317,7 +318,10 @@ static int add_worktree(const char *path, const char *refname,
 	if (ret)
 		goto done;
 
-	if (opts->new_branch)
+	if (opts->checkout_existing_branch)
+		fprintf_ln(stderr, _("checking out branch '%s'"),
+			   refname);
+	else if (opts->new_branch)
 		fprintf_ln(stderr, _("creating branch '%s'"), opts->new_branch);
 
 	fprintf(stderr, _("new worktree HEAD is now at %s"),
@@ -370,7 +374,18 @@ static const char *dwim_branch(const char *path, struct add_opts *opts)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	opts->new_branch = xstrndup(s, n);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		opts->checkout_existing_branch = 1;
+		strbuf_release(&ref);
+		UNLEAK(branchname);
+		return branchname;
+	}
+
+	opts->new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..ae602cf20e 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,26 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
+test_expect_success '"add" checks out existing branch of dwimd name' '
 	test_commit c1 &&
 	test_commit c2 &&
 	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
+	git worktree add precious &&
 	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+	(
+		cd precious &&
+		test_cmp_rev precious HEAD
+	)
+'
+
+test_expect_success '"add" auto-vivify fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
+'
+
+test_expect_success '"add --force" with existing dwimd name doesnt die' '
+	git worktree add --force test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.16.1.77.g8685934aa2


^ permalink raw reply related	[relevance 21%]

* [PATCH v5 0/6] worktree: teach "add" to check out existing branches
    2018-03-17 22:22 21%       ` [PATCH v4 4/4] " Thomas Gummerer
@ 2018-03-25 13:49  9%       ` Thomas Gummerer
  2018-03-25 13:49 21%         ` [PATCH v5 5/6] " Thomas Gummerer
                           ` (2 more replies)
  1 sibling, 3 replies; 200+ results
From: Thomas Gummerer @ 2018-03-25 13:49 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Thanks Eric for the review of the previous round and Duy and Junio for
additional comments.

Previous rounds are at <20180121120208.12760-1-t.gummerer@gmail.com>,
<20180204221305.28300-1-t.gummerer@gmail.com>,
<20180317220830.30963-1-t.gummerer@gmail.com> and
<20180317222219.4940-1-t.gummerer@gmail.com>.

This round should address all of Eric's comments from the previous round.

As explained in more detail in a reply to the review comment directly,
I did not add an enum to 'struct add_opts', for 'force_new_branch' and
'checkout_existing_branch', but instead removed 'force_new_branch'
from the struct as it's not required.

The rest of the updates are mainly in the user facing messages,
documentation and one added test.

Interdiff below:

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 98731b71a7..eaa6bf713f 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -67,7 +67,7 @@ doesn't exist, a new branch based on HEAD is automatically created as
 if `-b <branch>` was given.  If `<branch>` exists in the repository,
 it will be checked out in the new worktree, if it's not checked out
 anywhere else, otherwise the command will refuse to create the
-worktree.
+worktree (unless `--force` is used).
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index df5c0427ba..895838b943 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -28,7 +28,6 @@ struct add_opts {
 	int checkout;
 	int keep_locked;
 	const char *new_branch;
-	int force_new_branch;
 	int checkout_existing_branch;
 };
 
@@ -320,12 +319,12 @@ static int add_worktree(const char *path, const char *refname,
 		goto done;
 
 	if (opts->checkout_existing_branch)
-		fprintf(stderr, _("checking out branch '%s'"),
-			refname);
+		fprintf_ln(stderr, _("checking out branch '%s'"),
+			   refname);
 	else if (opts->new_branch)
-		fprintf(stderr, _("creating branch '%s'"), opts->new_branch);
+		fprintf_ln(stderr, _("creating branch '%s'"), opts->new_branch);
 
-	fprintf(stderr, _("worktree HEAD is now at %s"),
+	fprintf(stderr, _("new worktree HEAD is now at %s"),
 		find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
 
 	strbuf_reset(&sb);
@@ -434,8 +433,7 @@ static int add(int ac, const char **av, const char *prefix)
 	if (!strcmp(branch, "-"))
 		branch = "@{-1}";
 
-	opts.force_new_branch = !!new_branch_force;
-	if (opts.force_new_branch) {
+	if (new_branch_force) {
 		struct strbuf symref = STRBUF_INIT;
 
 		opts.new_branch = new_branch_force;
@@ -472,7 +470,7 @@ static int add(int ac, const char **av, const char *prefix)
 		struct child_process cp = CHILD_PROCESS_INIT;
 		cp.git_cmd = 1;
 		argv_array_push(&cp.args, "branch");
-		if (opts.force_new_branch)
+		if (new_branch_force)
 			argv_array_push(&cp.args, "--force");
 		argv_array_push(&cp.args, opts.new_branch);
 		argv_array_push(&cp.args, branch);
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 721b0e4c26..fb99f4c46f 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,15 +198,15 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify checks out existing branch' '
+test_expect_success '"add" checks out existing branch of dwimd name' '
 	test_commit c1 &&
 	test_commit c2 &&
-	git branch precious HEAD~1 &&
-	git worktree add precious &&
-	test_cmp_rev HEAD~1 precious &&
+	git branch dwim HEAD~1 &&
+	git worktree add dwim &&
+	test_cmp_rev HEAD~1 dwim &&
 	(
-		cd precious &&
-		test_cmp_rev precious HEAD
+		cd dwim &&
+		test_cmp_rev dwim HEAD
 	)
 '
 
@@ -216,6 +216,10 @@ test_expect_success '"add" auto-vivify fails with checked out branch' '
 	test_path_is_missing test-branch
 '
 
+test_expect_success '"add --force" with existing dwimd name doesnt die' '
+	git worktree add --force test-branch
+'
+
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
 	git worktree add --detach mish/mash &&
 	test_must_fail git rev-parse mash -- &&

Thomas Gummerer (6):
  worktree: improve message when creating a new worktree
  worktree: be clearer when "add" dwim-ery kicks in
  worktree: remove force_new_branch from struct add_opts
  worktree: factor out dwim_branch function
  worktree: teach "add" to check out existing branches
  t2025: rename now outdated branch name

 Documentation/git-worktree.txt |  9 ++++--
 builtin/worktree.c             | 64 +++++++++++++++++++++++++++++++-----------
 t/t2025-worktree-add.sh        | 23 +++++++++++----
 3 files changed, 72 insertions(+), 24 deletions(-)

-- 
2.16.1.77.g8685934aa2


^ permalink raw reply related	[relevance 9%]

* Re: [PATCH v4 4/4] worktree: teach "add" to check out existing branches
  2018-03-20  8:02  6%         ` Eric Sunshine
@ 2018-03-24 21:00  0%           ` Thomas Gummerer
  0 siblings, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-03-24 21:00 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git List, Nguyễn Thái Ngọc Duy, Junio C Hamano

On 03/20, Eric Sunshine wrote:
> On Sat, Mar 17, 2018 at 6:22 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:
> > [...]
> > However we can do a little better than that, and check the branch out if
> > it is not checked out anywhere else.  This will help users who just want
> > to check an existing branch out into a new worktree, and save a few
> > keystrokes.
> > [...]
> > We will still 'die()' if the branch is checked out in another worktree,
> > unless the --force flag is passed.
> >
> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> > ---
> > diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> > @@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
> >  If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
> > -then, as a convenience, a new branch based at HEAD is created automatically,
> > -as if `-b $(basename <path>)` was specified.
> > +then, as a convenience, a worktree with a branch named after
> > +`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
> > +doesn't exist, a new branch based on HEAD is automatically created as
> > +if `-b <branch>` was given.  If `<branch>` exists in the repository,
> > +it will be checked out in the new worktree, if it's not checked out
> > +anywhere else, otherwise the command will refuse to create the
> > +worktree.
> 
> Should this mention --force?
> 
>     ... refuse to create the worktree (unless --force is used).

Yeah, will add.

> > diff --git a/builtin/worktree.c b/builtin/worktree.c
> > @@ -29,6 +29,7 @@ struct add_opts {
> >         int keep_locked;
> >         const char *new_branch;
> >         int force_new_branch;
> > +       int checkout_existing_branch;
> 
> As 'force_new_branch' and 'checkout_existing_branch' are mutually
> exclusive, I wonder if they should be combined into an enum to make it
> easier to reason about.

I gave this a try, but I'm not sure the end result is nicer.  The
problem is that 'new_branch' and 'force_new_branch' both are mutually
exclusive with 'checkout_existing_branch', but 'force_new_branch' is a
"superset" of 'new_branch'.

I can't seem to think of a nice way to encode that, especially not
without duplicating information we're already carrying in
'new_branch'.  Looking at the code however I see that
'force_new_branch' is already only duplicating information that we
already have in a variable in the same function.  I think just
removing that duplication and keeping the 'checkout_existing_branch'
variable in the 'add_opts' would make most sense.

> > @@ -318,8 +319,11 @@ static int add_worktree(const char *path, const char *refname,
> > -       if (opts->new_branch)
> > -               fprintf(stderr, _("creating new branch '%s'"), opts->new_branch);
> > +       if (opts->checkout_existing_branch)
> > +               fprintf(stderr, _("checking out branch '%s'"),
> > +                       refname);
> 
> As with "creating branch" in 2/4, "checking out branch..." here is
> missing a newline.

Thanks will add.

> > +       else if (opts->new_branch)
> > +               fprintf(stderr, _("creating branch '%s'"), opts->new_branch);
> >
> >         fprintf(stderr, _("worktree HEAD is now at %s"),
> >                 find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
> > diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> > @@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
> > -test_expect_success '"add" auto-vivify does not clobber existing branch' '
> > +test_expect_success '"add" auto-vivify checks out existing branch' '
> >         test_commit c1 &&
> >         test_commit c2 &&
> >         git branch precious HEAD~1 &&
> > -       test_must_fail git worktree add precious &&
> > +       git worktree add precious &&
> >         test_cmp_rev HEAD~1 precious &&
> > -       test_path_is_missing precious
> > +       (
> > +               cd precious &&
> > +               test_cmp_rev precious HEAD
> > +       )
> > +'
> 
> This test is no longer checking auto-vivification ("bringing a new
> branch to life automatically"), but rather branch name inference, so
> the title is now misleading. Perhaps retitle it to '"add" checks out
> existing branch of dwim'd name' or something.
> 
> (The name "precious" is also now misleading since it's no longer
> checking that a precious branch does not get clobbered, however,
> changing the name would make the diff unnecessarily noisy, so it's
> probably okay as is.)

Good point.  I can add an additional patch with that rename, so the
changes here stay more obvious, but the end result would still end up
less confusing.

> > +test_expect_success '"add" auto-vivify fails with checked out branch' '
> > +       git checkout -b test-branch &&
> > +       test_must_fail git worktree add test-branch &&
> > +       test_path_is_missing test-branch
> >  '
> 
> Should we also have a corresponding test that this "fail" can be
> overridden by --force? (I realize that --force is tested elsewhere,
> but only with an explicitly-provided branch name, whereas this dwims
> the branch name.)

Yes, will add a test.  Thanks for your review!

^ permalink raw reply	[relevance 0%]

* [PATCH v2 01/36] t/helper: add an empty test-tool program
  @ 2018-03-24  7:44  4%   ` Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-03-24  7:44 UTC (permalink / raw)
  To: pclouds; +Cc: git, Eric Sunshine, Jeff Hostetler, Junio C Hamano

This will become an umbrella program that absorbs most [1] t/helper
programs in. By having a single executable binary we reduce disk usage
(libgit.a is replicated by every t/helper program) and shorten link
time a bit.

Running "make --jobs=1; du -sh t/helper" with ccache fully populated,
it takes 27 seconds and 277MB at the beginning of this series, 17
seconds and 42MB at the end.

[1] There are a couple programs that will not become part of
    test-tool: test-line-buffer and test-svn-fe have extra
    dependencies and test-fake-ssh's program name has to be a single
    word for some ssh tests.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile             |  6 +++++-
 t/helper/test-tool.c | 27 +++++++++++++++++++++++++++
 t/helper/test-tool.h |  4 ++++
 3 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 t/helper/test-tool.c
 create mode 100644 t/helper/test-tool.h

diff --git a/Makefile b/Makefile
index a1d8775adb..2376646e98 100644
--- a/Makefile
+++ b/Makefile
@@ -546,6 +546,7 @@ SCRIPT_PERL =
 SCRIPT_PYTHON =
 SCRIPT_SH =
 SCRIPT_LIB =
+TEST_BUILTINS_OBJS =
 TEST_PROGRAMS_NEED_X =
 
 # Having this variable in your environment would break pipelines because
@@ -690,6 +691,7 @@ TEST_PROGRAMS_NEED_X += test-string-list
 TEST_PROGRAMS_NEED_X += test-submodule-config
 TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
+TEST_PROGRAMS_NEED_X += test-tool
 TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
 TEST_PROGRAMS_NEED_X += test-wildmatch
 
@@ -2083,7 +2085,7 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
 VCSSVN_OBJS += vcs-svn/svndiff.o
 VCSSVN_OBJS += vcs-svn/svndump.o
 
-TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
+TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
 	$(VCSSVN_OBJS) \
@@ -2494,6 +2496,8 @@ t/helper/test-svn-fe$X: $(VCSSVN_LIB)
 
 .PRECIOUS: $(TEST_OBJS)
 
+t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
+
 t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
new file mode 100644
index 0000000000..c730f718ca
--- /dev/null
+++ b/t/helper/test-tool.c
@@ -0,0 +1,27 @@
+#include "git-compat-util.h"
+#include "test-tool.h"
+
+struct test_cmd {
+	const char *name;
+	int (*main)(int argc, const char **argv);
+};
+
+static struct test_cmd cmds[] = {
+};
+
+int cmd_main(int argc, const char **argv)
+{
+	int i;
+
+	if (argc < 2)
+		die("I need a test name!");
+
+	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+		if (!strcmp(cmds[i].name, argv[1])) {
+			argv++;
+			argc--;
+			return cmds[i].main(argc, argv);
+		}
+	}
+	die("There is no test named '%s'", argv[1]);
+}
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
new file mode 100644
index 0000000000..6ce57ae0cc
--- /dev/null
+++ b/t/helper/test-tool.h
@@ -0,0 +1,4 @@
+#ifndef __TEST_TOOL_H__
+#define __TEST_TOOL_H__
+
+#endif
-- 
2.17.0.rc0.348.gd5a49e0b6f


^ permalink raw reply related	[relevance 4%]

* [PATCH v2 01/36] t/helper: add an empty test-tool program
  @ 2018-03-24  7:42  4%   ` Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-03-24  7:42 UTC (permalink / raw)
  To: pclouds; +Cc: git, Eric Sunshine, Jeff Hostetler, Junio C Hamano

This will become an umbrella program that absorbs most [1] t/helper
programs in. By having a single executable binary we reduce disk usage
(libgit.a is replicated by every t/helper program) and shorten link
time a bit.

Running "make --jobs=1; du -sh t/helper" with ccache fully populated,
it takes 27 seconds and 277MB at the beginning of this series, 17
seconds and 42MB at the end.

[1] There are a couple programs that will not become part of
    test-tool: test-line-buffer and test-svn-fe have extra
    dependencies and test-fake-ssh's program name has to be a single
    word for some ssh tests.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile             |  6 +++++-
 t/helper/test-tool.c | 27 +++++++++++++++++++++++++++
 t/helper/test-tool.h |  4 ++++
 3 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 t/helper/test-tool.c
 create mode 100644 t/helper/test-tool.h

diff --git a/Makefile b/Makefile
index a1d8775adb..2376646e98 100644
--- a/Makefile
+++ b/Makefile
@@ -546,6 +546,7 @@ SCRIPT_PERL =
 SCRIPT_PYTHON =
 SCRIPT_SH =
 SCRIPT_LIB =
+TEST_BUILTINS_OBJS =
 TEST_PROGRAMS_NEED_X =
 
 # Having this variable in your environment would break pipelines because
@@ -690,6 +691,7 @@ TEST_PROGRAMS_NEED_X += test-string-list
 TEST_PROGRAMS_NEED_X += test-submodule-config
 TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
+TEST_PROGRAMS_NEED_X += test-tool
 TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
 TEST_PROGRAMS_NEED_X += test-wildmatch
 
@@ -2083,7 +2085,7 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
 VCSSVN_OBJS += vcs-svn/svndiff.o
 VCSSVN_OBJS += vcs-svn/svndump.o
 
-TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
+TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
 	$(VCSSVN_OBJS) \
@@ -2494,6 +2496,8 @@ t/helper/test-svn-fe$X: $(VCSSVN_LIB)
 
 .PRECIOUS: $(TEST_OBJS)
 
+t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
+
 t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
new file mode 100644
index 0000000000..c730f718ca
--- /dev/null
+++ b/t/helper/test-tool.c
@@ -0,0 +1,27 @@
+#include "git-compat-util.h"
+#include "test-tool.h"
+
+struct test_cmd {
+	const char *name;
+	int (*main)(int argc, const char **argv);
+};
+
+static struct test_cmd cmds[] = {
+};
+
+int cmd_main(int argc, const char **argv)
+{
+	int i;
+
+	if (argc < 2)
+		die("I need a test name!");
+
+	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+		if (!strcmp(cmds[i].name, argv[1])) {
+			argv++;
+			argc--;
+			return cmds[i].main(argc, argv);
+		}
+	}
+	die("There is no test named '%s'", argv[1]);
+}
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
new file mode 100644
index 0000000000..6ce57ae0cc
--- /dev/null
+++ b/t/helper/test-tool.h
@@ -0,0 +1,4 @@
+#ifndef __TEST_TOOL_H__
+#define __TEST_TOOL_H__
+
+#endif
-- 
2.17.0.rc0.348.gd5a49e0b6f


^ permalink raw reply related	[relevance 4%]

* Re: [PATCH v4 4/4] worktree: teach "add" to check out existing branches
  2018-03-17 22:22 21%       ` [PATCH v4 4/4] " Thomas Gummerer
@ 2018-03-20  8:02  6%         ` Eric Sunshine
  2018-03-24 21:00  0%           ` Thomas Gummerer
  0 siblings, 1 reply; 200+ results
From: Eric Sunshine @ 2018-03-20  8:02 UTC (permalink / raw)
  To: Thomas Gummerer
  Cc: Git List, Nguyễn Thái Ngọc Duy, Junio C Hamano

On Sat, Mar 17, 2018 at 6:22 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:
> [...]
> However we can do a little better than that, and check the branch out if
> it is not checked out anywhere else.  This will help users who just want
> to check an existing branch out into a new worktree, and save a few
> keystrokes.
> [...]
> We will still 'die()' if the branch is checked out in another worktree,
> unless the --force flag is passed.
>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---
> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> @@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
>  If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
> -then, as a convenience, a new branch based at HEAD is created automatically,
> -as if `-b $(basename <path>)` was specified.
> +then, as a convenience, a worktree with a branch named after
> +`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
> +doesn't exist, a new branch based on HEAD is automatically created as
> +if `-b <branch>` was given.  If `<branch>` exists in the repository,
> +it will be checked out in the new worktree, if it's not checked out
> +anywhere else, otherwise the command will refuse to create the
> +worktree.

Should this mention --force?

    ... refuse to create the worktree (unless --force is used).

> diff --git a/builtin/worktree.c b/builtin/worktree.c
> @@ -29,6 +29,7 @@ struct add_opts {
>         int keep_locked;
>         const char *new_branch;
>         int force_new_branch;
> +       int checkout_existing_branch;

As 'force_new_branch' and 'checkout_existing_branch' are mutually
exclusive, I wonder if they should be combined into an enum to make it
easier to reason about.

> @@ -318,8 +319,11 @@ static int add_worktree(const char *path, const char *refname,
> -       if (opts->new_branch)
> -               fprintf(stderr, _("creating new branch '%s'"), opts->new_branch);
> +       if (opts->checkout_existing_branch)
> +               fprintf(stderr, _("checking out branch '%s'"),
> +                       refname);

As with "creating branch" in 2/4, "checking out branch..." here is
missing a newline.

> +       else if (opts->new_branch)
> +               fprintf(stderr, _("creating branch '%s'"), opts->new_branch);
>
>         fprintf(stderr, _("worktree HEAD is now at %s"),
>                 find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> @@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
> -test_expect_success '"add" auto-vivify does not clobber existing branch' '
> +test_expect_success '"add" auto-vivify checks out existing branch' '
>         test_commit c1 &&
>         test_commit c2 &&
>         git branch precious HEAD~1 &&
> -       test_must_fail git worktree add precious &&
> +       git worktree add precious &&
>         test_cmp_rev HEAD~1 precious &&
> -       test_path_is_missing precious
> +       (
> +               cd precious &&
> +               test_cmp_rev precious HEAD
> +       )
> +'

This test is no longer checking auto-vivification ("bringing a new
branch to life automatically"), but rather branch name inference, so
the title is now misleading. Perhaps retitle it to '"add" checks out
existing branch of dwim'd name' or something.

(The name "precious" is also now misleading since it's no longer
checking that a precious branch does not get clobbered, however,
changing the name would make the diff unnecessarily noisy, so it's
probably okay as is.)

> +test_expect_success '"add" auto-vivify fails with checked out branch' '
> +       git checkout -b test-branch &&
> +       test_must_fail git worktree add test-branch &&
> +       test_path_is_missing test-branch
>  '

Should we also have a corresponding test that this "fail" can be
overridden by --force? (I realize that --force is tested elsewhere,
but only with an explicitly-provided branch name, whereas this dwims
the branch name.)

^ permalink raw reply	[relevance 6%]

* [PATCH v4 4/4] worktree: teach "add" to check out existing branches
  @ 2018-03-17 22:22 21%       ` Thomas Gummerer
  2018-03-20  8:02  6%         ` Eric Sunshine
  2018-03-25 13:49  9%       ` [PATCH v5 0/6] " Thomas Gummerer
  1 sibling, 1 reply; 200+ results
From: Thomas Gummerer @ 2018-03-17 22:22 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 21 ++++++++++++++++++---
 t/t2025-worktree-add.sh        | 15 ++++++++++++---
 3 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..98731b71a7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, a worktree with a branch named after
+`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` exists in the repository,
+it will be checked out in the new worktree, if it's not checked out
+anywhere else, otherwise the command will refuse to create the
+worktree.
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 52049b447a..df5c0427ba 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -29,6 +29,7 @@ struct add_opts {
 	int keep_locked;
 	const char *new_branch;
 	int force_new_branch;
+	int checkout_existing_branch;
 };
 
 static int show_only;
@@ -318,8 +319,11 @@ static int add_worktree(const char *path, const char *refname,
 	if (ret)
 		goto done;
 
-	if (opts->new_branch)
-		fprintf(stderr, _("creating new branch '%s'"), opts->new_branch);
+	if (opts->checkout_existing_branch)
+		fprintf(stderr, _("checking out branch '%s'"),
+			refname);
+	else if (opts->new_branch)
+		fprintf(stderr, _("creating branch '%s'"), opts->new_branch);
 
 	fprintf(stderr, _("worktree HEAD is now at %s"),
 		find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
@@ -371,7 +375,18 @@ static const char *dwim_branch(const char *path, struct add_opts *opts)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	opts->new_branch = xstrndup(s, n);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		opts->checkout_existing_branch = 1;
+		strbuf_release(&ref);
+		UNLEAK(branchname);
+		return branchname;
+	}
+
+	opts->new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..721b0e4c26 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
+test_expect_success '"add" auto-vivify checks out existing branch' '
 	test_commit c1 &&
 	test_commit c2 &&
 	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
+	git worktree add precious &&
 	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+	(
+		cd precious &&
+		test_cmp_rev precious HEAD
+	)
+'
+
+test_expect_success '"add" auto-vivify fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.17.0.rc0.231.g781580f06


^ permalink raw reply related	[relevance 21%]

* [PATCH v3 4/4] worktree: teach "add" to check out existing branches
  @ 2018-03-17 22:08 21%     ` Thomas Gummerer
    1 sibling, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-03-17 22:08 UTC (permalink / raw)
  To: git
  Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Junio C Hamano, Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 22 +++++++++++++++++++---
 t/t2025-worktree-add.sh        | 15 ++++++++++++---
 3 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..98731b71a7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, a worktree with a branch named after
+`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` exists in the repository,
+it will be checked out in the new worktree, if it's not checked out
+anywhere else, otherwise the command will refuse to create the
+worktree.
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 52049b447a..b5d273751f 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -29,6 +29,7 @@ struct add_opts {
 	int keep_locked;
 	const char *new_branch;
 	int force_new_branch;
+	int checkout_existing_branch;
 };
 
 static int show_only;
@@ -318,8 +319,11 @@ static int add_worktree(const char *path, const char *refname,
 	if (ret)
 		goto done;
 
-	if (opts->new_branch)
-		fprintf(stderr, _("creating new branch '%s'"), opts->new_branch);
+	if (opts->checkout_existing_branch)
+		fprintf(stderr, _("checking out branch '%s'"),
+			refname);
+	else if (opts->new_branch)
+		fprintf(stderr, _("creating branch '%s'"), opts->new_branch);
 
 	fprintf(stderr, _("worktree HEAD is now at %s"),
 		find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV));
@@ -371,7 +375,19 @@ static const char *dwim_branch(const char *path, struct add_opts *opts)
 {
 	int n;
 	const char *s = worktree_basename(path, &n);
-	opts->new_branch = xstrndup(s, n);
+	const char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	if (!strbuf_check_branch_ref(&ref, branchname) &&
+	    ref_exists(ref.buf)) {
+		*branch = branchname;
+		opts->checkout_existing_branch = 1;
+		strbuf_release(&ref);
+		UNLEAK(branchname);
+		return branchname;
+	}
+
+	opts->new_branch = branchname;
 	if (guess_remote) {
 		struct object_id oid;
 		const char *remote =
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..721b0e4c26 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
+test_expect_success '"add" auto-vivify checks out existing branch' '
 	test_commit c1 &&
 	test_commit c2 &&
 	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
+	git worktree add precious &&
 	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+	(
+		cd precious &&
+		test_cmp_rev precious HEAD
+	)
+'
+
+test_expect_success '"add" auto-vivify fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.17.0.rc0.231.g781580f06


^ permalink raw reply related	[relevance 21%]

* [PATCH 01/36] t/helper: add an empty test-tool program
  @ 2018-03-17  7:53  4% ` Nguyễn Thái Ngọc Duy
      2 siblings, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-03-17  7:53 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This will become an umbrella program that absorbs most [1] t/helper
programs in. By having a single executable binary we reduce disk usage
(libgit.a is replicated by every t/helper program) and shorten link
time a bit.

Running "make --jobs=1; du -sh t/helper" with ccache fully populated,
it takes 27 seconds and 277MB at the beginning of this series, 17
seconds and 42MB at the end.

[1] There are a couple programs that will not become part of
    test-tool: test-line-buffer and test-svn-fe have extra
    dependencies and test-fake-ssh's program name has to be a single
    word for some ssh tests.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile             |  6 +++++-
 t/helper/test-tool.c | 27 +++++++++++++++++++++++++++
 t/helper/test-tool.h |  4 ++++
 3 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 t/helper/test-tool.c
 create mode 100644 t/helper/test-tool.h

diff --git a/Makefile b/Makefile
index a1d8775adb..2376646e98 100644
--- a/Makefile
+++ b/Makefile
@@ -546,6 +546,7 @@ SCRIPT_PERL =
 SCRIPT_PYTHON =
 SCRIPT_SH =
 SCRIPT_LIB =
+TEST_BUILTINS_OBJS =
 TEST_PROGRAMS_NEED_X =
 
 # Having this variable in your environment would break pipelines because
@@ -690,6 +691,7 @@ TEST_PROGRAMS_NEED_X += test-string-list
 TEST_PROGRAMS_NEED_X += test-submodule-config
 TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
+TEST_PROGRAMS_NEED_X += test-tool
 TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
 TEST_PROGRAMS_NEED_X += test-wildmatch
 
@@ -2083,7 +2085,7 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
 VCSSVN_OBJS += vcs-svn/svndiff.o
 VCSSVN_OBJS += vcs-svn/svndump.o
 
-TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
+TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
 	$(VCSSVN_OBJS) \
@@ -2494,6 +2496,8 @@ t/helper/test-svn-fe$X: $(VCSSVN_LIB)
 
 .PRECIOUS: $(TEST_OBJS)
 
+t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
+
 t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
new file mode 100644
index 0000000000..c730f718ca
--- /dev/null
+++ b/t/helper/test-tool.c
@@ -0,0 +1,27 @@
+#include "git-compat-util.h"
+#include "test-tool.h"
+
+struct test_cmd {
+	const char *name;
+	int (*main)(int argc, const char **argv);
+};
+
+static struct test_cmd cmds[] = {
+};
+
+int cmd_main(int argc, const char **argv)
+{
+	int i;
+
+	if (argc < 2)
+		die("I need a test name!");
+
+	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+		if (!strcmp(cmds[i].name, argv[1])) {
+			argv++;
+			argc--;
+			return cmds[i].main(argc, argv);
+		}
+	}
+	die("There is no test named '%s'", argv[1]);
+}
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
new file mode 100644
index 0000000000..6ce57ae0cc
--- /dev/null
+++ b/t/helper/test-tool.h
@@ -0,0 +1,4 @@
+#ifndef __TEST_TOOL_H__
+#define __TEST_TOOL_H__
+
+#endif
-- 
2.16.2.903.gd04caf5039


^ permalink raw reply related	[relevance 4%]

* Re: [PATCH] strbuf_read_file(): preserve errno across close() call
  2018-02-23 22:17  4%       ` Junio C Hamano
@ 2018-02-23 22:55  0%         ` René Scharfe
  0 siblings, 0 replies; 200+ results
From: René Scharfe @ 2018-02-23 22:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Git List, Johannes Schindelin

Am 23.02.2018 um 23:17 schrieb Junio C Hamano:
> René Scharfe <l.s.r@web.de> writes:
> 
>> +#define IGNORE_ERROR(expr) do { int e_ = errno; expr; errno = e_; } while (0)
> 
> The macro certainly is a cute idea, but ...
> 
>> @@ -391,7 +393,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
>>   
>>   		if (got < 0) {
>>   			if (oldalloc == 0)
>> -				strbuf_release(sb);
>> +				IGNORE_ERROR(strbuf_release(sb));
>>   			else
>>   				strbuf_setlen(sb, oldlen);
>>   			return -1;
> 
> ... ideally, I would imagine that we wish we could write this hunk
> to something that expands to:
> 
> 		if (got < 0) {
> 			do {
>                                  int e_ = errno;
>                                  if (oldalloc == 0)
>                                          strbuf_release(sb);
>                                  else
>                                          strbuf_setlen(sb, oldlen);
>                                  errno = e_;
> 			} while (0);
> 			return -1;
> 
> no?  That is (1) we do not want to rely too much on knowing that
> strbuf_setlen() is very thin and does not touch errno, and hence (2)
> we want to mark not just a single expr but a block as "we know we
> got an error and errno from that error is more precious than what we
> do in this block to clean thihngs up".

Relying on that internal knowledge should be OK in strbuf.c, but in
this specific example we could of course do:

			if (oldalloc == 0)
				IGNORE_ERROR(strbuf_release(sb));
			else
				IGNORE_ERROR(strbuf_setlen(sb, oldlen));

I guess ignoring errors of whole blocks is not that common, based on
a quick search (git grep -W int.*_errno).  And in such a case we could
factor that code out into a separate function, if really needed.  Or
continue saving errno explicitly.

Compilers should be smart enough to avoid saving and restoring errno
between multiple uses of that macro, e.g. code like this would only do
it once, from what I saw when experimenting with the Compiler Explorer
(https://godbolt.org/):

	IGNORE_ERROR(close(fd1));
	IGNORE_ERROR(close(fd2));

> Of course, a pair of macros
> 
> 	#define IGNORE_ERROR_BEGIN do { int e_ = errno
> 	#define IGNORE_ERROR_END errno = e_; } while (0)
> 
> is probably the only way to do so in C, and that is already too ugly
> to live, so we cannot achieve the ideal.
> 
> So I dunno..

*shudder*

> 
>> @@ -617,9 +619,11 @@ ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
>>   	if (fd < 0)
>>   		return -1;
>>   	len = strbuf_read(sb, fd, hint);
>> -	close(fd);
>> -	if (len < 0)
>> +	if (len < 0) {
>> +		IGNORE_ERROR(close(fd));
>>   		return -1;
>> +	}
>> +	close(fd);
>>   
>>   	return len;
>>   }

^ permalink raw reply	[relevance 0%]

* Re: [PATCH] strbuf_read_file(): preserve errno across close() call
  @ 2018-02-23 22:17  4%       ` Junio C Hamano
  2018-02-23 22:55  0%         ` René Scharfe
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2018-02-23 22:17 UTC (permalink / raw)
  To: René Scharfe; +Cc: Jeff King, Git List, Johannes Schindelin

René Scharfe <l.s.r@web.de> writes:

> +#define IGNORE_ERROR(expr) do { int e_ = errno; expr; errno = e_; } while (0)

The macro certainly is a cute idea, but ...

> @@ -391,7 +393,7 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
>  
>  		if (got < 0) {
>  			if (oldalloc == 0)
> -				strbuf_release(sb);
> +				IGNORE_ERROR(strbuf_release(sb));
>  			else
>  				strbuf_setlen(sb, oldlen);
>  			return -1;

... ideally, I would imagine that we wish we could write this hunk
to something that expands to:

		if (got < 0) {
			do {
                                int e_ = errno;
                                if (oldalloc == 0)
                                        strbuf_release(sb);
                                else
                                        strbuf_setlen(sb, oldlen);
                                errno = e_;
			} while (0);
			return -1;

no?  That is (1) we do not want to rely too much on knowing that
strbuf_setlen() is very thin and does not touch errno, and hence (2)
we want to mark not just a single expr but a block as "we know we
got an error and errno from that error is more precious than what we
do in this block to clean thihngs up".

Of course, a pair of macros

	#define IGNORE_ERROR_BEGIN do { int e_ = errno
	#define IGNORE_ERROR_END errno = e_; } while (0)

is probably the only way to do so in C, and that is already too ugly
to live, so we cannot achieve the ideal.

So I dunno..

> @@ -617,9 +619,11 @@ ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
>  	if (fd < 0)
>  		return -1;
>  	len = strbuf_read(sb, fd, hint);
> -	close(fd);
> -	if (len < 0)
> +	if (len < 0) {
> +		IGNORE_ERROR(close(fd));
>  		return -1;
> +	}
> +	close(fd);
>  
>  	return len;
>  }

^ permalink raw reply	[relevance 4%]

* [PATCH v2 6/7] worktree remove: new command
  @ 2018-02-12  9:49  3%   ` Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-02-12  9:49 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Eric Sunshine, kaartic.sivaraam,
	Nguyễn Thái Ngọc Duy

This command allows to delete a worktree. Like 'move' you cannot
remove the main worktree, or one with submodules inside [1].

For deleting $GIT_WORK_TREE, Untracked files or any staged entries are
considered precious and therefore prevent removal by default. Ignored
files are not precious.

When it comes to deleting $GIT_DIR, there's no "clean" check because
there should not be any valuable data in there, except:

- HEAD reflog. There is nothing we can do about this until somebody
  steps up and implements the ref graveyard.

- Detached HEAD. Technically it can still be recovered. Although it
  may be nice to warn about orphan commits like 'git checkout' does.

[1] We do 'git status' with --ignore-submodules=all for safety
    anyway. But this needs a closer look by submodule people before we
    can allow deletion. For example, if a submodule is totally clean,
    but its repo not absorbed to the main .git dir, then deleting
    worktree also deletes the valuable .submodule repo too.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt         |  21 ++--
 builtin/worktree.c                     | 134 ++++++++++++++++++++++++-
 contrib/completion/git-completion.bash |   5 +-
 t/t2028-worktree-move.sh               |  30 ++++++
 4 files changed, 179 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index e6764ee8e0..d322acbc67 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -14,6 +14,7 @@ SYNOPSIS
 'git worktree lock' [--reason <string>] <worktree>
 'git worktree move' <worktree> <new-path>
 'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree remove' [--force] <worktree>
 'git worktree unlock' <worktree>
 
 DESCRIPTION
@@ -85,6 +86,13 @@ prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
 
+remove::
+
+Remove a working tree. Only clean working trees (no untracked files
+and no modification in tracked files) can be removed. Unclean working
+trees or ones with submodules can be removed with `--force`. The main
+working tree cannot be removed.
+
 unlock::
 
 Unlock a working tree, allowing it to be pruned, moved or deleted.
@@ -94,9 +102,10 @@ OPTIONS
 
 -f::
 --force::
-	By default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and
-	is already checked out by another working tree. This option overrides
-	that safeguard.
+	By default, `add` refuses to create a new working tree when
+	`<commit-ish>` is a branch name and is already checked out by
+	another working tree and `remove` refuses to remove an unclean
+	working tree. This option overrides that safeguard.
 
 -b <new-branch>::
 -B <new-branch>::
@@ -278,12 +287,6 @@ Multiple checkout in general is still experimental, and the support
 for submodules is incomplete. It is NOT recommended to make multiple
 checkouts of a superproject.
 
-git-worktree could provide more automation for tasks currently
-performed manually, such as:
-
-- `remove` to remove a linked working tree and its administrative files (and
-  warn if the working tree is dirty)
-
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4789cebe11..990e47b315 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -19,6 +19,7 @@ static const char * const worktree_usage[] = {
 	N_("git worktree lock [<options>] <path>"),
 	N_("git worktree move <worktree> <new-path>"),
 	N_("git worktree prune [<options>]"),
+	N_("git worktree remove [<options>] <worktree>"),
 	N_("git worktree unlock <path>"),
 	NULL
 };
@@ -624,7 +625,7 @@ static void validate_no_submodules(const struct worktree *wt)
 	discard_index(&istate);
 
 	if (found_submodules)
-		die(_("working trees containing submodules cannot be moved"));
+		die(_("working trees containing submodules cannot be moved or removed"));
 }
 
 static int move_worktree(int ac, const char **av, const char *prefix)
@@ -688,6 +689,135 @@ static int move_worktree(int ac, const char **av, const char *prefix)
 	return 0;
 }
 
+/*
+ * Note, "git status --porcelain" is used to determine if it's safe to
+ * delete a whole worktree. "git status" does not ignore user
+ * configuration, so if a normal "git status" shows "clean" for the
+ * user, then it's ok to remove it.
+ *
+ * This assumption may be a bad one. We may want to ignore
+ * (potentially bad) user settings and only delete a worktree when
+ * it's absolutely safe to do so from _our_ point of view because we
+ * know better.
+ */
+static void check_clean_worktree(struct worktree *wt,
+				 const char *original_path)
+{
+	struct argv_array child_env = ARGV_ARRAY_INIT;
+	struct child_process cp;
+	char buf[1];
+	int ret;
+
+	/*
+	 * Until we sort this out, all submodules are "dirty" and
+	 * will abort this function.
+	 */
+	validate_no_submodules(wt);
+
+	argv_array_pushf(&child_env, "%s=%s/.git",
+			 GIT_DIR_ENVIRONMENT, wt->path);
+	argv_array_pushf(&child_env, "%s=%s",
+			 GIT_WORK_TREE_ENVIRONMENT, wt->path);
+	memset(&cp, 0, sizeof(cp));
+	argv_array_pushl(&cp.args, "status",
+			 "--porcelain", "--ignore-submodules=none",
+			 NULL);
+	cp.env = child_env.argv;
+	cp.git_cmd = 1;
+	cp.dir = wt->path;
+	cp.out = -1;
+	ret = start_command(&cp);
+	if (ret)
+		die_errno(_("failed to run 'git status' on '%s'"),
+			  original_path);
+	ret = xread(cp.out, buf, sizeof(buf));
+	if (ret)
+		die(_("'%s' is dirty, use --force to delete it"),
+		    original_path);
+	close(cp.out);
+	ret = finish_command(&cp);
+	if (ret)
+		die_errno(_("failed to run 'git status' on '%s', code %d"),
+			  original_path, ret);
+}
+
+static int delete_git_work_tree(struct worktree *wt)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	strbuf_addstr(&sb, wt->path);
+	if (remove_dir_recursively(&sb, 0)) {
+		error_errno(_("failed to delete '%s'"), sb.buf);
+		ret = -1;
+	}
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int delete_git_dir(struct worktree *wt)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	strbuf_addstr(&sb, git_common_path("worktrees/%s", wt->id));
+	if (remove_dir_recursively(&sb, 0)) {
+		error_errno(_("failed to delete '%s'"), sb.buf);
+		ret = -1;
+	}
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int remove_worktree(int ac, const char **av, const char *prefix)
+{
+	int force = 0;
+	struct option options[] = {
+		OPT_BOOL(0, "force", &force,
+			 N_("force removing even if the worktree is dirty")),
+		OPT_END()
+	};
+	struct worktree **worktrees, *wt;
+	struct strbuf errmsg = STRBUF_INIT;
+	const char *reason;
+	int ret = 0;
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (ac != 1)
+		usage_with_options(worktree_usage, options);
+
+	worktrees = get_worktrees(0);
+	wt = find_worktree(worktrees, prefix, av[0]);
+	if (!wt)
+		die(_("'%s' is not a working tree"), av[0]);
+	if (is_main_worktree(wt))
+		die(_("'%s' is a main working tree"), av[0]);
+	reason = is_worktree_locked(wt);
+	if (reason) {
+		if (*reason)
+			die(_("cannot remove a locked working tree, lock reason: %s"),
+			    reason);
+		die(_("cannot remove a locked working tree"));
+	}
+	if (validate_worktree(wt, &errmsg))
+		die(_("validation failed, cannot remove working tree: %s"),
+		    errmsg.buf);
+	strbuf_release(&errmsg);
+
+	if (!force)
+		check_clean_worktree(wt, av[0]);
+
+	ret |= delete_git_work_tree(wt);
+	/*
+	 * continue on even if ret is non-zero, there's no going back
+	 * from here.
+	 */
+	ret |= delete_git_dir(wt);
+
+	free_worktrees(worktrees);
+	return ret;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -712,5 +842,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 		return unlock_worktree(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "move"))
 		return move_worktree(ac - 1, av + 1, prefix);
+	if (!strcmp(av[1], "remove"))
+		return remove_worktree(ac - 1, av + 1, prefix);
 	usage_with_options(worktree_usage, options);
 }
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index b87d387686..ff4a39631e 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -3087,7 +3087,7 @@ _git_whatchanged ()
 
 _git_worktree ()
 {
-	local subcommands="add list lock move prune unlock"
+	local subcommands="add list lock move prune remove unlock"
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
 	if [ -z "$subcommand" ]; then
 		__gitcomp "$subcommands"
@@ -3105,6 +3105,9 @@ _git_worktree ()
 		prune,--*)
 			__gitcomp "--dry-run --expire --verbose"
 			;;
+		remove,--*)
+			__gitcomp "--force"
+			;;
 		*)
 			;;
 		esac
diff --git a/t/t2028-worktree-move.sh b/t/t2028-worktree-move.sh
index deb486cd8e..4718c4552f 100755
--- a/t/t2028-worktree-move.sh
+++ b/t/t2028-worktree-move.sh
@@ -96,4 +96,34 @@ test_expect_success 'move worktree to another dir' '
 	test_cmp expected2 actual2
 '
 
+test_expect_success 'remove main worktree' '
+	test_must_fail git worktree remove .
+'
+
+test_expect_success 'move some-dir/destination back' '
+	git worktree move some-dir/destination destination
+'
+
+test_expect_success 'remove locked worktree' '
+	git worktree lock destination &&
+	test_when_finished "git worktree unlock destination" &&
+	test_must_fail git worktree remove destination
+'
+
+test_expect_success 'remove worktree with dirty tracked file' '
+	echo dirty >>destination/init.t &&
+	test_when_finished "git -C destination checkout init.t" &&
+	test_must_fail git worktree remove destination
+'
+
+test_expect_success 'remove worktree with untracked file' '
+	: >destination/untracked &&
+	test_must_fail git worktree remove destination
+'
+
+test_expect_success 'force remove worktree with untracked file' '
+	git worktree remove --force destination &&
+	test_path_is_missing destination
+'
+
 test_done
-- 
2.16.1.399.g632f88eed1


^ permalink raw reply related	[relevance 3%]

* [PATCH v2 3/3] worktree: teach "add" to check out existing branches
  @ 2018-02-04 22:13 21%   ` Thomas Gummerer
    1 sibling, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-02-04 22:13 UTC (permalink / raw)
  To: git; +Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a branch with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---
 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 31 +++++++++++++++++++++++--------
 t/t2025-worktree-add.sh        | 15 ++++++++++++---
 3 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..98731b71a7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, a worktree with a branch named after
+`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` exists in the repository,
+it will be checked out in the new worktree, if it's not checked out
+anywhere else, otherwise the command will refuse to create the
+worktree.
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 74a853c2a3..ea420bb90b 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -29,6 +29,7 @@ struct add_opts {
 	int keep_locked;
 	const char *new_branch;
 	int force_new_branch;
+	int checkout_existing_branch;
 };
 
 static int show_only;
@@ -320,7 +321,10 @@ static int add_worktree(const char *path, const char *refname,
 	if (ret)
 		goto done;
 
-	if (opts->new_branch)
+	if (opts->checkout_existing_branch)
+		fprintf(stderr, _(", checking out existing branch '%s'"),
+			refname);
+	else if (opts->new_branch)
 		fprintf(stderr, _(", creating new branch '%s'"), opts->new_branch);
 
 	fprintf(stderr, _(", setting HEAD to %s"),
@@ -423,14 +427,25 @@ static int add(int ac, const char **av, const char *prefix)
 	if (ac < 2 && !opts.new_branch && !opts.detach) {
 		int n;
 		const char *s = worktree_basename(path, &n);
-		opts.new_branch = xstrndup(s, n);
-		if (guess_remote) {
-			struct object_id oid;
-			const char *remote =
-				unique_tracking_name(opts.new_branch, &oid);
-			if (remote)
-				branch = remote;
+		const char *branchname = xstrndup(s, n);
+		struct strbuf ref = STRBUF_INIT;
+
+		if (!strbuf_check_branch_ref(&ref, branchname) &&
+		    ref_exists(ref.buf)) {
+			branch = branchname;
+			opts.checkout_existing_branch = 1;
+			UNLEAK(branch);
+		} else {
+			opts.new_branch = branchname;
+			if (guess_remote) {
+				struct object_id oid;
+				const char *remote =
+					unique_tracking_name(opts.new_branch, &oid);
+				if (remote)
+					branch = remote;
+			}
 		}
+		strbuf_release(&ref);
 	}
 
 	if (ac == 2 && !opts.new_branch && !opts.detach) {
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..721b0e4c26 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
+test_expect_success '"add" auto-vivify checks out existing branch' '
 	test_commit c1 &&
 	test_commit c2 &&
 	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
+	git worktree add precious &&
 	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+	(
+		cd precious &&
+		test_cmp_rev precious HEAD
+	)
+'
+
+test_expect_success '"add" auto-vivify fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.16.1.101.gde0f0111ea


^ permalink raw reply related	[relevance 21%]

* Re: [PATCH v2 1/1] setup: recognise extensions.objectFormat
  @ 2018-01-30  1:38  4%   ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2018-01-30  1:38 UTC (permalink / raw)
  To: Patryk Obara
  Cc: git, Junio C Hamano, Nguyễn Thái Ngọc Duy,
	Johannes.Schindelin, sbeller, brian m . carlson

On Sun, Jan 28, 2018 at 01:36:17AM +0100, Patryk Obara wrote:

> This extension selects which hashing algorithm from vtable should be
> used for reading and writing objects in the object store.  At the moment
> supports only single value (sha-1).
> 
> In case value of objectFormat is an unknown hashing algorithm, Git
> command will fail with following message:
> 
>   fatal: unknown repository extensions found:
> 	  objectformat = <value>
> 
> To indicate, that this specific objectFormat value is not recognised.

I don't have a strong opinion on this, but it does feel a little funny
to add this extension now, before we quite know what the code that uses
it is going to look like (or maybe we're farther along there than I
realize).

What do we gain by doing this now as opposed to later? By the design of
the extension code, we should complain on older versions anyway. And by
doing it now we carry a small risk that it might not give us the
interface we want, and it will be slightly harder to paper over this
failed direction.

All that said, if people like brian, who are thinking more about this
transition than I am, are onboard, I'm OK with it.

> The objectFormat extension is not allowed in repository marked as
> version 0 to prevent any possibility of accidentally writing a NewHash
> object in the sha-1 object store. This extension behaviour is different
> than preciousObjects extension (which is allowed in repo version 0).

It wasn't intended that anyone would specify preciousObjects with repo
version 0. It's a dangerous misconfiguration (because versions which
predate the extensions mechanism won't actually respect it at all!).

So we probably ought to complain loudly on having anything in
extensions.* when the repositoryformat is less than 1.

I originally wrote it the other way out of an abundance of
backward-compatibility. After all "extension.*" doesn't mean anything in
format 0, and somebody _could_ have added such a config key for their
own purposes. But that's a pretty weak argument, and if we are going to
start marking some extensions as forbidden there, we might as well do
them all.

Something like this:

diff --git a/cache.h b/cache.h
index d8b975a571..259c4a5361 100644
--- a/cache.h
+++ b/cache.h
@@ -921,6 +921,7 @@ struct repository_format {
 	int is_bare;
 	int hash_algo;
 	char *work_tree;
+	int extensions_seen;
 	struct string_list unknown_extensions;
 };
 
diff --git a/setup.c b/setup.c
index 8cc34186ce..85dfcf330b 100644
--- a/setup.c
+++ b/setup.c
@@ -413,6 +413,7 @@ static int check_repo_format(const char *var, const char *value, void *vdata)
 	if (strcmp(var, "core.repositoryformatversion") == 0)
 		data->version = git_config_int(var, value);
 	else if (skip_prefix(var, "extensions.", &ext)) {
+		data->extensions_seen = 1;
 		/*
 		 * record any known extensions here; otherwise,
 		 * we fall through to recording it as unknown, and
@@ -503,6 +504,11 @@ int verify_repository_format(const struct repository_format *format,
 		return -1;
 	}
 
+	if (format->version < 1 && format->extensions_seen) {
+		strbuf_addstr(err, _("extensions found but repo version is < 1"));
+		return -1;
+	}
+
 	if (format->version >= 1 && format->unknown_extensions.nr) {
 		int i;
 
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index ce4cff13bb..9e9f67d756 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -80,9 +80,10 @@ while read outcome version extensions; do
 done <<\EOF
 allow 0
 allow 1
+abort 0 noop
 allow 1 noop
+abort 0 no-such-extension
 abort 1 no-such-extension
-allow 0 no-such-extension
 EOF
 
 test_expect_success 'precious-objects allowed' '

^ permalink raw reply related	[relevance 4%]

* [PATCH 6/7] worktree remove: new command
  @ 2018-01-24  9:53  3% ` Nguyễn Thái Ngọc Duy
    1 sibling, 0 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:53 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Eric Sunshine, kaartic.sivaraam,
	Nguyễn Thái Ngọc Duy

This command allows to delete a worktree. Like 'move' you cannot
remove the main worktree, or one with submodules inside [1].

For deleting $GIT_WORK_TREE, Untracked files or any staged entries are
considered precious and therefore prevent removal by default. Ignored
files are not precious.

When it comes to deleting $GIT_DIR, there's no "clean" check because
there should not be any valuable data in there, except:

- HEAD reflog. There is nothing we can do about this until somebody
  steps up and implements the ref graveyard.

- Detached HEAD. Technically it can still be recovered. Although it
  may be nice to warn about orphan commits like 'git checkout' does.

[1] We do 'git status' with --ignore-submodules=all for safety
    anyway. But this needs a closer look by submodule people before we
    can allow deletion. For example, if a submodule is totally clean,
    but its repo not absorbed to the main .git dir, then deleting
    worktree also deletes the valuable .submodule repo too.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-worktree.txt         |  21 +++---
 builtin/worktree.c                     | 131 ++++++++++++++++++++++++++++++++-
 contrib/completion/git-completion.bash |   5 +-
 t/t2028-worktree-move.sh               |  26 +++++++
 4 files changed, 172 insertions(+), 11 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 24bb69de50..6f83723d9a 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -14,6 +14,7 @@ SYNOPSIS
 'git worktree lock' [--reason <string>] <worktree>
 'git worktree move' <worktree> <new-path>
 'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree remove' [--force] <worktree>
 'git worktree unlock' <worktree>
 
 DESCRIPTION
@@ -89,6 +90,13 @@ prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
 
+remove::
+
+Remove a working tree. Only clean working trees (no untracked files
+and no modification in tracked files) can be removed. Unclean working
+trees or ones with submodules can be removed with `--force`. The main
+working tree cannot be removed.
+
 unlock::
 
 Unlock a working tree, allowing it to be pruned, moved or deleted.
@@ -98,9 +106,10 @@ OPTIONS
 
 -f::
 --force::
-	By default, `add` refuses to create a new working tree when `<commit-ish>` is a branch name and
-	is already checked out by another working tree. This option overrides
-	that safeguard.
+	By default, `add` refuses to create a new working tree when
+	`<commit-ish>` is a branch name and is already checked out by
+	another working tree and `remove` refuses to remove an unclean
+	working tree. This option overrides that safeguard.
 
 -b <new-branch>::
 -B <new-branch>::
@@ -282,12 +291,6 @@ Multiple checkout in general is still experimental, and the support
 for submodules is incomplete. It is NOT recommended to make multiple
 checkouts of a superproject.
 
-git-worktree could provide more automation for tasks currently
-performed manually, such as:
-
-- `remove` to remove a linked working tree and its administrative files (and
-  warn if the working tree is dirty)
-
 GIT
 ---
 Part of the linkgit:git[1] suite
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 15980a0a49..8b027375d7 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -19,6 +19,7 @@ static const char * const worktree_usage[] = {
 	N_("git worktree lock [<options>] <path>"),
 	N_("git worktree move <worktree> <new-path>"),
 	N_("git worktree prune [<options>]"),
+	N_("git worktree remove [<options>] <worktree>"),
 	N_("git worktree unlock <path>"),
 	NULL
 };
@@ -624,7 +625,7 @@ static void validate_no_submodules(const struct worktree *wt)
 	discard_index(&istate);
 
 	if (found_submodules)
-		die(_("working trees containing submodules cannot be moved"));
+		die(_("working trees containing submodules cannot be moved or removed"));
 }
 
 static int move_worktree(int ac, const char **av, const char *prefix)
@@ -688,6 +689,132 @@ static int move_worktree(int ac, const char **av, const char *prefix)
 	return 0;
 }
 
+/*
+ * Note, "git status --porcelain" is used to determine if it's safe to
+ * delete a whole worktree. "git status" does not ignore user
+ * configuration, so if a normal "git status" shows "clean" for the
+ * user, then it's ok to remove it.
+ *
+ * This assumption may be a bad one. We may want to ignore
+ * (potentially bad) user settings and only delete a worktree when
+ * it's absolutely safe to do so from _our_ point of view because we
+ * know better.
+ */
+static void check_clean_worktree(struct worktree *wt,
+				 const char *original_path)
+{
+	struct argv_array child_env = ARGV_ARRAY_INIT;
+	struct child_process cp;
+	char buf[1];
+	int ret;
+
+	validate_no_submodules(wt);
+
+	argv_array_pushf(&child_env, "%s=%s/.git",
+			 GIT_DIR_ENVIRONMENT, wt->path);
+	argv_array_pushf(&child_env, "%s=%s",
+			 GIT_WORK_TREE_ENVIRONMENT, wt->path);
+	memset(&cp, 0, sizeof(cp));
+	argv_array_pushl(&cp.args, "status",
+			 "--porcelain", "--ignore-submodules=none",
+			 NULL);
+	cp.env = child_env.argv;
+	cp.git_cmd = 1;
+	cp.dir = wt->path;
+	cp.out = -1;
+	ret = start_command(&cp);
+	if (ret)
+		die_errno(_("failed to run git-status on '%s'"),
+			  original_path);
+	ret = xread(cp.out, buf, sizeof(buf));
+	if (ret)
+		die(_("'%s' is dirty, use --force to delete it"),
+		    original_path);
+	close(cp.out);
+	ret = finish_command(&cp);
+	if (ret)
+		die_errno(_("failed to run git-status on '%s', code %d"),
+			  original_path, ret);
+}
+
+static int delete_git_work_tree(struct worktree *wt)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	strbuf_addstr(&sb, wt->path);
+	if (remove_dir_recursively(&sb, 0)) {
+		error_errno(_("failed to delete '%s'"), sb.buf);
+		ret = -1;
+	}
+	strbuf_release(&sb);
+
+	return ret;
+}
+
+static int delete_git_dir(struct worktree *wt)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	strbuf_addstr(&sb, git_common_path("worktrees/%s", wt->id));
+	if (remove_dir_recursively(&sb, 0)) {
+		error_errno(_("failed to delete '%s'"), sb.buf);
+		ret = -1;
+	}
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int remove_worktree(int ac, const char **av, const char *prefix)
+{
+	int force = 0;
+	struct option options[] = {
+		OPT_BOOL(0, "force", &force,
+			 N_("force removing even if the worktree is dirty")),
+		OPT_END()
+	};
+	struct worktree **worktrees, *wt;
+	struct strbuf errmsg = STRBUF_INIT;
+	const char *reason;
+	int ret = 0;
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (ac != 1)
+		usage_with_options(worktree_usage, options);
+
+	worktrees = get_worktrees(0);
+	wt = find_worktree(worktrees, prefix, av[0]);
+	if (!wt)
+		die(_("'%s' is not a working tree"), av[0]);
+	if (is_main_worktree(wt))
+		die(_("'%s' is a main working tree"), av[0]);
+	reason = is_worktree_locked(wt);
+	if (reason) {
+		if (*reason)
+			die(_("cannot remove a locked working tree, lock reason: %s"),
+			    reason);
+		die(_("cannot remove a locked working tree"));
+	}
+	if (validate_worktree(wt, &errmsg))
+		die(_("validation failed, cannot remove working tree:\n%s"),
+		    errmsg.buf);
+	strbuf_release(&errmsg);
+
+	if (!force)
+		check_clean_worktree(wt, av[0]);
+
+	ret |= delete_git_work_tree(wt);
+	/*
+	 * continue on even if ret is non-zero, there's no going back
+	 * from here.
+	 */
+	ret |= delete_git_dir(wt);
+
+	free_worktrees(worktrees);
+	return ret;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -712,5 +839,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 		return unlock_worktree(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "move"))
 		return move_worktree(ac - 1, av + 1, prefix);
+	if (!strcmp(av[1], "remove"))
+		return remove_worktree(ac - 1, av + 1, prefix);
 	usage_with_options(worktree_usage, options);
 }
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index b87d387686..ff4a39631e 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -3087,7 +3087,7 @@ _git_whatchanged ()
 
 _git_worktree ()
 {
-	local subcommands="add list lock move prune unlock"
+	local subcommands="add list lock move prune remove unlock"
 	local subcommand="$(__git_find_on_cmdline "$subcommands")"
 	if [ -z "$subcommand" ]; then
 		__gitcomp "$subcommands"
@@ -3105,6 +3105,9 @@ _git_worktree ()
 		prune,--*)
 			__gitcomp "--dry-run --expire --verbose"
 			;;
+		remove,--*)
+			__gitcomp "--force"
+			;;
 		*)
 			;;
 		esac
diff --git a/t/t2028-worktree-move.sh b/t/t2028-worktree-move.sh
index bef420a086..b3105eaaed 100755
--- a/t/t2028-worktree-move.sh
+++ b/t/t2028-worktree-move.sh
@@ -90,4 +90,30 @@ test_expect_success 'move main worktree' '
 	test_must_fail git worktree move . def
 '
 
+test_expect_success 'remove main worktree' '
+	test_must_fail git worktree remove .
+'
+
+test_expect_success 'remove locked worktree' '
+	git worktree lock destination &&
+	test_must_fail git worktree remove destination &&
+	git worktree unlock destination
+'
+
+test_expect_success 'remove worktree with dirty tracked file' '
+	echo dirty >>destination/init.t &&
+	test_must_fail git worktree remove destination
+'
+
+test_expect_success 'remove worktree with untracked file' '
+	git -C destination checkout init.t &&
+	: >destination/untracked &&
+	test_must_fail git worktree remove destination
+'
+
+test_expect_success 'force remove worktree with untracked file' '
+	git worktree remove --force destination &&
+	test_path_is_missing destination
+'
+
 test_done
-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply related	[relevance 3%]

* Re: [PATCH] worktree: teach "add" to check out existing branches
  2018-01-22 11:18  0% ` Duy Nguyen
@ 2018-01-22 20:17  0%   ` Thomas Gummerer
  0 siblings, 0 replies; 200+ results
From: Thomas Gummerer @ 2018-01-22 20:17 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List, Eric Sunshine

On 01/22, Duy Nguyen wrote:
> On Sun, Jan 21, 2018 at 7:02 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:
> > [...]
> >  +
> >  If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
> > -then, as a convenience, a new branch based at HEAD is created automatically,
> > -as if `-b $(basename <path>)` was specified.
> > +then, as a convenience, a worktree with a branch named after
> > +`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
> > +doesn't exist, a new branch based on HEAD is automatically created as
> > +if `-b <branch>` was given.  If `<branch>` exists in the repository,
> > +it will be checked out in the new worktree, if it's not checked out
> > +anywhere else, otherwise the command will refuse to create the
> > +worktree.
> 
> It starts getting a bit too magical to me. We probably should print
> something "switching to branch..." or "creating new branch ..."  to
> let people know what decision was taken, unless --quiet is given. Yeah
> I know --quiet does not exist. You don't need to add it now either
> since nobody has asked for it.

I think that's a good idea.  I'll add that, thanks.

> More or less related to this, there was a question [1] whether we
> could do better than $(basename <path>) for determining branch name.
> Since you're doing start to check if a branch exists, people may start
> asking to check for branch "foo/bar" from the path abc/foo/bar instead
> of just branch "bar".

Thanks for pointing me at this.  I feel like we might get ourselves
some backwards compatibility worries when doing that.  Lets say
someone has a branch 'feature/a', using 'git worktree feature/a' would
currently create a new branch 'a', and does not die.

I'd guess most users would want 'feature/a' checked out in that case,
but we can't exactly be sure we won't break anyones workflow here.
With your suggestion I guess that would be mitigated somehow as it
shows which action is taken, but dunno.

Should we hide this behaviour behind a flag, and plan for it
eventually becoming the default?

> [1] https://github.com/git-for-windows/git/issues/1390
> 
> >
> >  list::
> >
> > diff --git a/builtin/worktree.c b/builtin/worktree.c
> > index 7cef5b120b..148a864bb9 100644
> > --- a/builtin/worktree.c
> > +++ b/builtin/worktree.c
> > @@ -411,13 +411,21 @@ static int add(int ac, const char **av, const char *prefix)
> >         if (ac < 2 && !opts.new_branch && !opts.detach) {
> >                 int n;
> >                 const char *s = worktree_basename(path, &n);
> > -               opts.new_branch = xstrndup(s, n);
> > -               if (guess_remote) {
> > -                       struct object_id oid;
> > -                       const char *remote =
> > -                               unique_tracking_name(opts.new_branch, &oid);
> > -                       if (remote)
> > -                               branch = remote;
> > +               const char *branchname = xstrndup(s, n);
> > +               struct strbuf ref = STRBUF_INIT;
> 
> Perhaps a blank line after this to separate var declarations and the rest.

Will add. 

> > +               if (!strbuf_check_branch_ref(&ref, branchname) &&
> > +                   ref_exists(ref.buf)) {
> > +                       branch = branchname;
> 
> Hmm.. do we need UNLEAK(branch);? Maybe you should try valgrind, I'm not sure.

Good question, I'll have a look, thanks.

> > +                       opts.checkout = 1;
> > +               } else {
> > +                       opts.new_branch = branchname;
> > +                       if (guess_remote) {
> > +                               struct object_id oid;
> > +                               const char *remote =
> > +                                       unique_tracking_name(opts.new_branch, &oid);
> > +                               if (remote)
> > +                                       branch = remote;
> > +                       }
> >                 }
> >         }
> >
> > diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> > index 2b95944973..721b0e4c26 100755
> > --- a/t/t2025-worktree-add.sh
> > +++ b/t/t2025-worktree-add.sh
> > @@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
> >         test_cmp_rev HEAD bat
> >  '
> >
> > -test_expect_success '"add" auto-vivify does not clobber existing branch' '
> > +test_expect_success '"add" auto-vivify checks out existing branch' '
> >         test_commit c1 &&
> >         test_commit c2 &&
> >         git branch precious HEAD~1 &&
> > -       test_must_fail git worktree add precious &&
> > +       git worktree add precious &&
> >         test_cmp_rev HEAD~1 precious &&
> > -       test_path_is_missing precious
> > +       (
> > +               cd precious &&
> > +               test_cmp_rev precious HEAD
> > +       )
> > +'
> > +
> > +test_expect_success '"add" auto-vivify fails with checked out branch' '
> > +       git checkout -b test-branch &&
> > +       test_must_fail git worktree add test-branch &&
> > +       test_path_is_missing test-branch
> >  '
> >
> >  test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
> > --
> > 2.16.0.312.g896df04e46
> >
> 
> 
> 
> -- 
> Duy

^ permalink raw reply	[relevance 0%]

* Re: [PATCH] worktree: teach "add" to check out existing branches
  2018-01-21 12:02 21% [PATCH] worktree: teach "add" to check out existing branches Thomas Gummerer
@ 2018-01-22 11:18  0% ` Duy Nguyen
  2018-01-22 20:17  0%   ` Thomas Gummerer
    1 sibling, 1 reply; 200+ results
From: Duy Nguyen @ 2018-01-22 11:18 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: Git Mailing List, Eric Sunshine

On Sun, Jan 21, 2018 at 7:02 PM, Thomas Gummerer <t.gummerer@gmail.com> wrote:
> Currently 'git worktree add <path>' creates a new branch named after the
> basename of the path by default.  If a branch with that name already
> exists, the command refuses to do anything, unless the '--force' option
> is given.
>
> However we can do a little better than that, and check the branch out if
> it is not checked out anywhere else.  This will help users who just want
> to check an existing branch out into a new worktree, and save a few
> keystrokes.
>
> As the current behaviour is to simply 'die()' when a brach with the name
> of the basename of the path already exists, there are no backwards
> compatibility worries here.
>
> We will still 'die()' if the branch is checked out in another worktree,
> unless the --force flag is passed.
>
> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
> ---
>
> This is a follow-up to
> https://public-inbox.org/git/20171118181345.GC32324@hank/, where this
> was first suggested, but I didn't want to do it as part of that
> series.  Now I finally got around to implementing it.
>
>  Documentation/git-worktree.txt |  9 +++++++--
>  builtin/worktree.c             | 22 +++++++++++++++-------
>  t/t2025-worktree-add.sh        | 15 ++++++++++++---
>  3 files changed, 34 insertions(+), 12 deletions(-)
>
> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> index 41585f535d..98731b71a7 100644
> --- a/Documentation/git-worktree.txt
> +++ b/Documentation/git-worktree.txt
> @@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
>  ------------
>  +
>  If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
> -then, as a convenience, a new branch based at HEAD is created automatically,
> -as if `-b $(basename <path>)` was specified.
> +then, as a convenience, a worktree with a branch named after
> +`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
> +doesn't exist, a new branch based on HEAD is automatically created as
> +if `-b <branch>` was given.  If `<branch>` exists in the repository,
> +it will be checked out in the new worktree, if it's not checked out
> +anywhere else, otherwise the command will refuse to create the
> +worktree.

It starts getting a bit too magical to me. We probably should print
something "switching to branch..." or "creating new branch ..."  to
let people know what decision was taken, unless --quiet is given. Yeah
I know --quiet does not exist. You don't need to add it now either
since nobody has asked for it.

More or less related to this, there was a question [1] whether we
could do better than $(basename <path>) for determining branch name.
Since you're doing start to check if a branch exists, people may start
asking to check for branch "foo/bar" from the path abc/foo/bar instead
of just branch "bar".

[1] https://github.com/git-for-windows/git/issues/1390

>
>  list::
>
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 7cef5b120b..148a864bb9 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -411,13 +411,21 @@ static int add(int ac, const char **av, const char *prefix)
>         if (ac < 2 && !opts.new_branch && !opts.detach) {
>                 int n;
>                 const char *s = worktree_basename(path, &n);
> -               opts.new_branch = xstrndup(s, n);
> -               if (guess_remote) {
> -                       struct object_id oid;
> -                       const char *remote =
> -                               unique_tracking_name(opts.new_branch, &oid);
> -                       if (remote)
> -                               branch = remote;
> +               const char *branchname = xstrndup(s, n);
> +               struct strbuf ref = STRBUF_INIT;

Perhaps a blank line after this to separate var declarations and the rest.

> +               if (!strbuf_check_branch_ref(&ref, branchname) &&
> +                   ref_exists(ref.buf)) {
> +                       branch = branchname;

Hmm.. do we need UNLEAK(branch);? Maybe you should try valgrind, I'm not sure.

> +                       opts.checkout = 1;
> +               } else {
> +                       opts.new_branch = branchname;
> +                       if (guess_remote) {
> +                               struct object_id oid;
> +                               const char *remote =
> +                                       unique_tracking_name(opts.new_branch, &oid);
> +                               if (remote)
> +                                       branch = remote;
> +                       }
>                 }
>         }
>
> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> index 2b95944973..721b0e4c26 100755
> --- a/t/t2025-worktree-add.sh
> +++ b/t/t2025-worktree-add.sh
> @@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
>         test_cmp_rev HEAD bat
>  '
>
> -test_expect_success '"add" auto-vivify does not clobber existing branch' '
> +test_expect_success '"add" auto-vivify checks out existing branch' '
>         test_commit c1 &&
>         test_commit c2 &&
>         git branch precious HEAD~1 &&
> -       test_must_fail git worktree add precious &&
> +       git worktree add precious &&
>         test_cmp_rev HEAD~1 precious &&
> -       test_path_is_missing precious
> +       (
> +               cd precious &&
> +               test_cmp_rev precious HEAD
> +       )
> +'
> +
> +test_expect_success '"add" auto-vivify fails with checked out branch' '
> +       git checkout -b test-branch &&
> +       test_must_fail git worktree add test-branch &&
> +       test_path_is_missing test-branch
>  '
>
>  test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
> --
> 2.16.0.312.g896df04e46
>



-- 
Duy

^ permalink raw reply	[relevance 0%]

* [PATCH] worktree: teach "add" to check out existing branches
@ 2018-01-21 12:02 21% Thomas Gummerer
  2018-01-22 11:18  0% ` Duy Nguyen
    0 siblings, 2 replies; 200+ results
From: Thomas Gummerer @ 2018-01-21 12:02 UTC (permalink / raw)
  To: git; +Cc: Eric Sunshine, Nguyễn Thái Ngọc Duy,
	Thomas Gummerer

Currently 'git worktree add <path>' creates a new branch named after the
basename of the path by default.  If a branch with that name already
exists, the command refuses to do anything, unless the '--force' option
is given.

However we can do a little better than that, and check the branch out if
it is not checked out anywhere else.  This will help users who just want
to check an existing branch out into a new worktree, and save a few
keystrokes.

As the current behaviour is to simply 'die()' when a brach with the name
of the basename of the path already exists, there are no backwards
compatibility worries here.

We will still 'die()' if the branch is checked out in another worktree,
unless the --force flag is passed.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
---

This is a follow-up to
https://public-inbox.org/git/20171118181345.GC32324@hank/, where this
was first suggested, but I didn't want to do it as part of that
series.  Now I finally got around to implementing it.

 Documentation/git-worktree.txt |  9 +++++++--
 builtin/worktree.c             | 22 +++++++++++++++-------
 t/t2025-worktree-add.sh        | 15 ++++++++++++---
 3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 41585f535d..98731b71a7 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -61,8 +61,13 @@ $ git worktree add --track -b <branch> <path> <remote>/<branch>
 ------------
 +
 If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
-then, as a convenience, a new branch based at HEAD is created automatically,
-as if `-b $(basename <path>)` was specified.
+then, as a convenience, a worktree with a branch named after
+`$(basename <path>)` (call it `<branch>`) is created.  If `<branch>`
+doesn't exist, a new branch based on HEAD is automatically created as
+if `-b <branch>` was given.  If `<branch>` exists in the repository,
+it will be checked out in the new worktree, if it's not checked out
+anywhere else, otherwise the command will refuse to create the
+worktree.
 
 list::
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 7cef5b120b..148a864bb9 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -411,13 +411,21 @@ static int add(int ac, const char **av, const char *prefix)
 	if (ac < 2 && !opts.new_branch && !opts.detach) {
 		int n;
 		const char *s = worktree_basename(path, &n);
-		opts.new_branch = xstrndup(s, n);
-		if (guess_remote) {
-			struct object_id oid;
-			const char *remote =
-				unique_tracking_name(opts.new_branch, &oid);
-			if (remote)
-				branch = remote;
+		const char *branchname = xstrndup(s, n);
+		struct strbuf ref = STRBUF_INIT;
+		if (!strbuf_check_branch_ref(&ref, branchname) &&
+		    ref_exists(ref.buf)) {
+			branch = branchname;
+			opts.checkout = 1;
+		} else {
+			opts.new_branch = branchname;
+			if (guess_remote) {
+				struct object_id oid;
+				const char *remote =
+					unique_tracking_name(opts.new_branch, &oid);
+				if (remote)
+					branch = remote;
+			}
 		}
 	}
 
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 2b95944973..721b0e4c26 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -198,13 +198,22 @@ test_expect_success '"add" with <branch> omitted' '
 	test_cmp_rev HEAD bat
 '
 
-test_expect_success '"add" auto-vivify does not clobber existing branch' '
+test_expect_success '"add" auto-vivify checks out existing branch' '
 	test_commit c1 &&
 	test_commit c2 &&
 	git branch precious HEAD~1 &&
-	test_must_fail git worktree add precious &&
+	git worktree add precious &&
 	test_cmp_rev HEAD~1 precious &&
-	test_path_is_missing precious
+	(
+		cd precious &&
+		test_cmp_rev precious HEAD
+	)
+'
+
+test_expect_success '"add" auto-vivify fails with checked out branch' '
+	git checkout -b test-branch &&
+	test_must_fail git worktree add test-branch &&
+	test_path_is_missing test-branch
 '
 
 test_expect_success '"add" no auto-vivify with --detach and <branch> omitted' '
-- 
2.16.0.312.g896df04e46


^ permalink raw reply related	[relevance 21%]

* Re: Bring together merge and rebase
  2017-12-25  3:52  0% ` Theodore Ts'o
@ 2017-12-27  4:35  0%   ` Carl Baldwin
  0 siblings, 0 replies; 200+ results
From: Carl Baldwin @ 2017-12-27  4:35 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Git Mailing List

On Sun, Dec 24, 2017 at 10:52:15PM -0500, Theodore Ts'o wrote:
> Here's another potential use case.  The stable kernels (e.g., 3.18.y,
> 4.4.y, 4.9.y, etc.) have cherry picks from the the upstream kernel,
> and this is handled by putting in the commit body something like this:
> 
>     [ Upstream commit 3a4b77cd47bb837b8557595ec7425f281f2ca1fe ]

I think replaces could apply to cherry picks like this too. The more I
think about it, I actually think that replaces isn't a bad name for it
in the cherry pick context. When you cherry pick a commit, you create a
new commit that is derived from it and stands in for or replaces it in
the new context. It is a stretch but I don't think it is that bad.

You can tell that it is a cherry pick because the referenced commit's
history is not reachable in the current context.

Though we could consider some different names like "derivedfrom",
"obsoletes", "succeeds", "supersedes", "supplants"

> ----
> 
> And here's yet another use case.  For internal Google kernel
> development, we maintain a kernel that has a large number of patches
> on top of a kernel version.  When we backport an upstream fix (say,
> one that first appeared in the 4.12 version of the upstream kernel),
> we include a line in the commit body that looks like this:
> 
> Upstream-4.12-SHA1: 5649645d725c73df4302428ee4e02c869248b4c5
> 
> This is useful, because when we switch to use a newer upstream kernel,
> we need make sure we can account for all patches that were built on
> top of the 3xx kernel (which might have been using 4.10, for the sake
> of argument), to the 4xx kernel series (which might be using 4.15 ---
> the version numbers have been changed to protect the innocent).  This
> means going through each and every patch that was on top of the 3xx
> kernel, and if it has a line such as "Upstream 4.12-SHA1", we know
> that it will already be included in a 4.15 based kernel, so we don't
> need to worry about carrying that patch forward.

Are 3xx and 4xx internal version numbers? If I understand correctly, in
your example, 3xx is the heavily patched internal kernel based on 4.10
and 4xx is the internal patched version of 4.15. I think I'm following
so far.

Let's say that you used a "replaces" reference instead of your
"Upstream-4.12-SHA1" reference. The only piece of metadata that is
missing is the "4.12" of your string. However, you could replicate this
with some set arithmetic. If the sha1 referred to by "replaces" exists
in the set of commits reachable from 4.15 then you've answered the same
question.

> In other cases, we might decide that the patch is no longer needed.
> It could be because the patch has already be included upstream, in
> which case we might check in a commit with an empty patch body, but
> whose header contains something like this in the 4xx kernel:
> 
> Origin-3xx-SHA1: fe546bdfc46a92255ebbaa908dc3a942bc422faa
> Upstream-Dropped-4.11-SHA1: d90dc0ae7c264735bfc5ac354c44ce2e

So, the first reference is the old commit that patched the 3xx series?
What is the second reference? What is "4.11" indicating? Is that the
patch that was included in the upstream kernel that obsoleted your 3xx
patch?

If I understood that correctly. You could use a "replaces" reference for
the first line and the second line would still have to be included as a
separate header in your commit message? Does this mean "replaces" is not
useful in your case? I don't think so.

> Or we could decide that the commit is no longer no longer needed ---

no longer no longer needed? Is this a double negative indicating that it
is needed again? Or, is it a mistake?

> perhaps because the relevant subsystem was completely rewritten and
> the functionality was added in a different way.  Then we might have
> just have an empty commit with an explanation of why the commit is no
> longer needed and the commit body would have the metadata:
> 
> Origin-Dropped-3xx-SHA1: 26f49fcbb45e4bc18ad5b52dc93c3afe

The metadata in this reference indicates that it was dropped since 3xx.
Doesn't the empty body (and maybe a commit message saying dropping a
patch) indicate this if a "references" pointer were used instead? The
3xx part of the metadata could be derived again by set arithmetic.

> Or perhaps the commit is still needed, and for various reasons the
> commit was never upstreamed; perhaps because it's only useful for
> Google-specific hardware, or the patch was rejected upstream.  The we
> will have a cherry-pick that would include in the body:
> 
> Origin-3xx-SHA1: 8f3b6df74b9b4ec3ab615effb984c1b5

Replaces reference and set arithmetic.

> (Note: all commits that are added in the rebase workflow, even the
> empty commits that just have the Origin-Dropped-3xx-SHA1 or
> Upstream-Droped-4.11-SHA1 headers, are patch reviewed through Gerrit,
> so we have an audited, second-engineer review to make sure each commit
> in the 3xx kernel that Google had been carrying had the correct
> disposition when rebasing to the 4xx kernel.)

This is great! I designed a strikingly similar workflow for local
patches to Openstack Neutron about four years ago. Each time we moved
forward to a new version of upstream, we went through a very similar
process. I don't have access to those scripts any longer but here is
what I recall.

With each now upstream version, we'd generate a list of commits we
created locally using git. I recall it being a fairly simple set
difference between the upstream tag and our downstream tag. I wrote
scripts that would take each of them and proposed them as new gerrit
reviews against the new upstream. I made sure to keep the same gerrit
change-id as the old one in the new review. Gerrit allowed this because
it was a new branch for each now revision and gerrit allows the same
change-id in different reviews as long as the branch is different. I'm
not sure if you kept the same change-id or not but it was very useful to
me. I could see the history of the patch applied to various upstream
versions with the click of a link in gerrit.

My automated script would cherry pick but wouldn't attempt to resolve
any conflicts. Instead, it would commit the conflict markers exactly as
they occurred and flag the review as conflicted. A human would have to
come along and recreate the cherry pick in their own workspace to
resolve the conflicts. Then they'd post the result to the same gerrit
review as the second patch set. This way, the resolution of the
conflicts could easily be reviewed in the tool.

We'd run our CI against each and every one also to be sure that we
weren't breaking it.

Sometimes, patches were rendered obsolete by something upstream. In this
case, we would close the gerrit review without merging indicating that
the patch was dropped and the reason.

For patches that we proposed upstream, we'd use the same gerrit id in
the upstream review. This helped us tie them together and identify them
as equivalent patches.

When all of the gerrit reviews for all of the patches were merged, we'd
merge the result to master. I recall doing something special for this
final merge but I don't recall exactly what it was. Maybe it was to use
the "theirs" strategy or something like that.

I remember having a script called "delinearize" which would actually
find the minimum chain of preceding patches that had to come before a
given one in order for it to rebase cleanly to the upstream base. Most
of the time, the patches rebased cleanly to the upstream. This meant
that they really didn't depend on any of the patches that came before
them. This was very useful because it allowed us humans to switch
between a bunch of mostly independent gerrit reviews for the newly
cherry-picked patches and do a lot of things in parallel. We could merge
them in any order as long as they went through the entire review
process.

> The point is that for this much more complex, real-world workflow, we
> need much *more* metadata than a simple "Replaces" metadata.  (And we
> also have other metadata --- for example, we have a "Tested: " trailer
> that explains how to test the commit, or which unit test can and
> should be used to test this commit, combined with a link to the test
> log in our automated unit tester that has the test run, and a
> "Rebase-Tested-4xx: " trailer that might just have the URL to the test
> log when the commit was rebased since the testing instructions in the
> Tested: trailer is still relevant.)

So far, I haven't seen that it is that much more complex. I've actually
had experience doing practically the same thing. Yes, it was a complex
process but we didn't need much more than the gerrit-id in the reviews
and an external dashboard listing the patches out with a link to each
review. Even the dashboard was pretty much obsolete once the whole
process was declared done for a given upstream revision.

Your "Tested" trailer sounds completely orthogonal. I'm not sure that
showing a need for other orthogonal metadata is necessarily a good
argument against my proposal. It doesn't seem relevant.

> And since this metadata is not really needed by the core git
> machinery, we just use text trailers in the commit body; it's not hard
> to write code which parses this out of the git commit.
> 
> > Various git commands will have to learn how to handle this kind of
> > history. For example, things like fetch, push, gc, and others that
> > move history around and clean out orphaned history should treat
> > anything reachable through `replaces` pointers as precious. Log and
> > related history commands may need new switches to traverse the history
> > differently in different situations.
> 
> I'd encourage you to think very hard about how exactly "git log" and
> "gitk" might actually deal with these links.  In the Google kernel
> development use cases, we use different repos for the 3xx and 4xx
> kernels.  It would be possible to make hot links for the
> Original-3xx-SHA1: trailers, but you couldn't do it using gitk.  It
> would actually have to be a completely new tool.  (And we do have new
> tools, most especially a dashboard so we can keep track of how many
> commits in the 3xx kernel still have to be rebased to the 4xx kernel,
> or can be confirmed to be in the upstream kernel, or can be confirmed
> to be dropped.  We have a *large* number of patches that we carry, so
> it's a multi-month effort involving a large number of engineers
> working together to do a kernel rebase operation from a 4.x upstream
> kernel to a 4.y upstream kernel.  So having a dashboard is useful
> because we can see whether a particular subsystem team is ahead or
> behind the curve in terms of handling those commits which are their
> responsibility.)
> 
> My experience, from seeing these much more complex use cases ---
> starting with something as simple as the Linux Kernel Stable Kernel
> Series, and extending to something much more complex such as the
> workflow that is used to support a Google Kernel Rebase, is that using
> just a simple extra "Replaces" pointer in the commit header is not
> nearly expressive enough.  And, if you make it a core part of the
> commit data structure, there are all sorts of compatibility headaches
> with older versions of git that wouldn't know about it.  And if it

The more I think about this, the less I worry. Be sure that you're using 

> then turns out it's not sufficient more the more complex workflows
> *anyway*, maybe adding a new "replace" pointer in the core git data
> structures isn't worth it.  It might be that just keeping such things
> as trailers in the commit body might be the better way to go.

It doesn't need to be everything to everyone to be useful. I hope to
show in this thread that it is useful enough to be a compelling addition
to git. I think I've also shown that it could be used as a part of your
more complex workflow. Maybe even a bigger part of it than you had
realized.

Carl

^ permalink raw reply	[relevance 0%]

* Re: Bring together merge and rebase
  2017-12-23  6:10  3% Bring together merge and rebase Carl Baldwin
  2017-12-23 18:59  0% ` Ævar Arnfjörð Bjarmason
  2017-12-25  3:52  0% ` Theodore Ts'o
@ 2017-12-26  4:08  0% ` Mike Hommey
  2 siblings, 0 replies; 200+ results
From: Mike Hommey @ 2017-12-26  4:08 UTC (permalink / raw)
  To: Carl Baldwin; +Cc: Git Mailing List

On Fri, Dec 22, 2017 at 11:10:19PM -0700, Carl Baldwin wrote:
> The big contention among git users is whether to rebase or to merge
> changes [2][3] while iterating. I used to firmly believe that merging
> was the way to go and rebase was harmful. More recently, I have worked
> in some environments where I saw rebase used very effectively while
> iterating on changes and I relaxed my stance a lot. Now, I'm on the
> fence. I appreciate the strengths and weaknesses of both approaches. I
> waffle between the two depending on the situation, the tools being
> used, and I guess, to some extent, my mood.
> 
> I think what git needs is something brand new that brings the two
> together and has all of the advantages of both approaches. Let me
> explain what I've got in mind...
> 
> I've been calling this proposal `git replay` or `git replace` but I'd
> like to hear other suggestions for what to name it. It works like
> rebase except with one very important difference. Instead of orphaning
> the original commit, it keeps a pointer to it in the commit just like
> a `parent` entry but calls it `replaces` instead to distinguish it
> from regular history. In the resulting commit history, following
> `parent` pointers shows exactly the same history as if the commit had
> been rebased. Meanwhile, the history of iterating on the change itself
> is available by following `replaces` pointers. The new commit replaces
> the old one but keeps it around to record how the change evolved.
> 
> The git history now has two dimensions. The first shows a cleaned up
> history where fix ups and code review feedback have been rolled into
> the original changes and changes can possibly be ordered in a nice
> linear progression that is much easier to understand. The second
> drills into the history of a change. There is no loss and you don't
> change history in a way that will cause problems for others who have
> the older commits.
> 
> Replay handles collaboration between multiple authors on a single
> change. This is difficult and prone to accidental loss when using
> rebase and it results in a complex history when done with merge. With
> replay, collaborators could merge while collaborating on a single
> change and a record of each one's contributions can be preserved.
> Attempting this level of collaboration caused me many headaches when I
> worked with the gerrit workflow (which in many ways, I like a lot).
> 
> I blogged about this proposal earlier this year when I first thought
> of it [1]. I got busy and didn't think about it for a while. Now with
> a little time off of work, I've come back to revisit it. The blog
> entry has a few examples showing how it works and how the history will
> look in a few examples. Take a look.
> 
> Various git commands will have to learn how to handle this kind of
> history. For example, things like fetch, push, gc, and others that
> move history around and clean out orphaned history should treat
> anything reachable through `replaces` pointers as precious. Log and
> related history commands may need new switches to traverse the history
> differently in different situations. Bisect is a interesting one. I
> tend to think that bisect should prefer the regular commit history but
> have the ability to drill into the change history if necessary.
> 
> In my opinion, this proposal would bring together rebase and merge in
> a powerful way and could end the contention. Thanks for your
> consideration.

FWIW, your proposal has a lot in common (but is not quite equivalent) to
mercurial's obsolescence markers and changeset evolution features.

Mike

^ permalink raw reply	[relevance 0%]

* Re: Bring together merge and rebase
  2017-12-23  6:10  3% Bring together merge and rebase Carl Baldwin
  2017-12-23 18:59  0% ` Ævar Arnfjörð Bjarmason
@ 2017-12-25  3:52  0% ` Theodore Ts'o
  2017-12-27  4:35  0%   ` Carl Baldwin
  2017-12-26  4:08  0% ` Mike Hommey
  2 siblings, 1 reply; 200+ results
From: Theodore Ts'o @ 2017-12-25  3:52 UTC (permalink / raw)
  To: Carl Baldwin; +Cc: Git Mailing List

On Fri, Dec 22, 2017 at 11:10:19PM -0700, Carl Baldwin wrote:
> I've been calling this proposal `git replay` or `git replace` but I'd
> like to hear other suggestions for what to name it. It works like
> rebase except with one very important difference. Instead of orphaning
> the original commit, it keeps a pointer to it in the commit just like
> a `parent` entry but calls it `replaces` instead to distinguish it
> from regular history. In the resulting commit history, following
> `parent` pointers shows exactly the same history as if the commit had
> been rebased. Meanwhile, the history of iterating on the change itself
> is available by following `replaces` pointers. The new commit replaces
> the old one but keeps it around to record how the change evolved.

As a suggestion, before diving into the technical details of your
proposal, it might be useful consider the usage scenario you are
targetting.  Things like "git rebase" and "git merge" and your
proposed "git replace/replay" are *mechanisms*.

But how they fit into a particular workflow is much more important
from a design perspective, and given that there are many different git
workflows which are used by different projects, and by different
developers within a particular project.

For example, rebase gets used in many different ways, and many of the
debates when people talk about "git rebase" being evil generally
presuppose a particular workflow that that the advocate has in mind.
If someone is using git rebase or git commit --amend before git
commits have ever been pushed out to a public repository, or to anyone
else, that's a very different case where it has been visible
elsewhere.  Even the the most strident, "you must never rewrite a
commit and all history must be preserved" generally don't insist that
every single edit must be preserved on the theory that "all history is
valuable".

> The git history now has two dimensions. The first shows a cleaned up
> history where fix ups and code review feedback have been rolled into
> the original changes and changes can possibly be ordered in a nice
> linear progression that is much easier to understand. The second
> drills into the history of a change. There is no loss and you don't
> change history in a way that will cause problems for others who have
> the older commits.

If your goal is to preserve the history of the change, one of the
problems with any git-centric solution is that you generally lose the
code review feedback and the discussions that are involved with a
commit.  Just simply preserving the different versions of the commits
is going to lose a huge amount of the context that makes the history
valuable.

So for example, I would claim that if *that* is your goal, a better
solution is to use Gerrit, so that all of the different versions of
the commits are preserved along with the line-by-line comments and
discussions that were part of the code review.  In that model, each
commit has something like this in the commit trailer:

Change-Id: I8d89b33683274451bcd6bfbaf75bce98

You can then cut and paste the Change-Id into the Gerrit user
interface, and see the different commits, more important, the
discussion surrounding each change.


If the complaint about Gerrit is that it's not a core part of Git, the
challenge is (a) how to carry the code review comments in the git
repository, and (b) do so in a while that it doesn't bloat the core
repository, since most of the time, you *don't* want or need to keep a
local copy of all of the code review comments going back since the
beginning of the project.

-------------

Here's another potential use case.  The stable kernels (e.g., 3.18.y,
4.4.y, 4.9.y, etc.) have cherry picks from the the upstream kernel,
and this is handled by putting in the commit body something like this:

    [ Upstream commit 3a4b77cd47bb837b8557595ec7425f281f2ca1fe ]

----

And here's yet another use case.  For internal Google kernel
development, we maintain a kernel that has a large number of patches
on top of a kernel version.  When we backport an upstream fix (say,
one that first appeared in the 4.12 version of the upstream kernel),
we include a line in the commit body that looks like this:

Upstream-4.12-SHA1: 5649645d725c73df4302428ee4e02c869248b4c5

This is useful, because when we switch to use a newer upstream kernel,
we need make sure we can account for all patches that were built on
top of the 3xx kernel (which might have been using 4.10, for the sake
of argument), to the 4xx kernel series (which might be using 4.15 ---
the version numbers have been changed to protect the innocent).  This
means going through each and every patch that was on top of the 3xx
kernel, and if it has a line such as "Upstream 4.12-SHA1", we know
that it will already be included in a 4.15 based kernel, so we don't
need to worry about carrying that patch forward.

In other cases, we might decide that the patch is no longer needed.
It could be because the patch has already be included upstream, in
which case we might check in a commit with an empty patch body, but
whose header contains something like this in the 4xx kernel:

Origin-3xx-SHA1: fe546bdfc46a92255ebbaa908dc3a942bc422faa
Upstream-Dropped-4.11-SHA1: d90dc0ae7c264735bfc5ac354c44ce2e

Or we could decide that the commit is no longer no longer needed ---
perhaps because the relevant subsystem was completely rewritten and
the functionality was added in a different way.  Then we might have
just have an empty commit with an explanation of why the commit is no
longer needed and the commit body would have the metadata:

Origin-Dropped-3xx-SHA1: 26f49fcbb45e4bc18ad5b52dc93c3afe

Or perhaps the commit is still needed, and for various reasons the
commit was never upstreamed; perhaps because it's only useful for
Google-specific hardware, or the patch was rejected upstream.  The we
will have a cherry-pick that would include in the body:

Origin-3xx-SHA1: 8f3b6df74b9b4ec3ab615effb984c1b5


(Note: all commits that are added in the rebase workflow, even the
empty commits that just have the Origin-Dropped-3xx-SHA1 or
Upstream-Droped-4.11-SHA1 headers, are patch reviewed through Gerrit,
so we have an audited, second-engineer review to make sure each commit
in the 3xx kernel that Google had been carrying had the correct
disposition when rebasing to the 4xx kernel.)

The point is that for this much more complex, real-world workflow, we
need much *more* metadata than a simple "Replaces" metadata.  (And we
also have other metadata --- for example, we have a "Tested: " trailer
that explains how to test the commit, or which unit test can and
should be used to test this commit, combined with a link to the test
log in our automated unit tester that has the test run, and a
"Rebase-Tested-4xx: " trailer that might just have the URL to the test
log when the commit was rebased since the testing instructions in the
Tested: trailer is still relevant.)

And since this metadata is not really needed by the core git
machinery, we just use text trailers in the commit body; it's not hard
to write code which parses this out of the git commit.

> Various git commands will have to learn how to handle this kind of
> history. For example, things like fetch, push, gc, and others that
> move history around and clean out orphaned history should treat
> anything reachable through `replaces` pointers as precious. Log and
> related history commands may need new switches to traverse the history
> differently in different situations.

I'd encourage you to think very hard about how exactly "git log" and
"gitk" might actually deal with these links.  In the Google kernel
development use cases, we use different repos for the 3xx and 4xx
kernels.  It would be possible to make hot links for the
Original-3xx-SHA1: trailers, but you couldn't do it using gitk.  It
would actually have to be a completely new tool.  (And we do have new
tools, most especially a dashboard so we can keep track of how many
commits in the 3xx kernel still have to be rebased to the 4xx kernel,
or can be confirmed to be in the upstream kernel, or can be confirmed
to be dropped.  We have a *large* number of patches that we carry, so
it's a multi-month effort involving a large number of engineers
working together to do a kernel rebase operation from a 4.x upstream
kernel to a 4.y upstream kernel.  So having a dashboard is useful
because we can see whether a particular subsystem team is ahead or
behind the curve in terms of handling those commits which are their
responsibility.)


My experience, from seeing these much more complex use cases ---
starting with something as simple as the Linux Kernel Stable Kernel
Series, and extending to something much more complex such as the
workflow that is used to support a Google Kernel Rebase, is that using
just a simple extra "Replaces" pointer in the commit header is not
nearly expressive enough.  And, if you make it a core part of the
commit data structure, there are all sorts of compatibility headaches
with older versions of git that wouldn't know about it.  And if it
then turns out it's not sufficient more the more complex workflows
*anyway*, maybe adding a new "replace" pointer in the core git data
structures isn't worth it.  It might be that just keeping such things
as trailers in the commit body might be the better way to go.

Cheers,

						- Ted

^ permalink raw reply	[relevance 0%]

* Re: Bring together merge and rebase
  2017-12-23 18:59  0% ` Ævar Arnfjörð Bjarmason
@ 2017-12-23 22:30  0%   ` Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2017-12-23 22:30 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Carl Baldwin, Git Mailing List

[-- Attachment #1: Type: text/plain, Size: 10651 bytes --]

Hi Ævar,

On Sat, 23 Dec 2017, Ævar Arnfjörð Bjarmason wrote:

> On Sat, Dec 23 2017, Carl Baldwin jotted:
> 
> > The big contention among git users is whether to rebase or to merge
> > changes [2][3] while iterating. I used to firmly believe that merging
> > was the way to go and rebase was harmful. More recently, I have worked
> > in some environments where I saw rebase used very effectively while
> > iterating on changes and I relaxed my stance a lot. Now, I'm on the
> > fence. I appreciate the strengths and weaknesses of both approaches. I
> > waffle between the two depending on the situation, the tools being
> > used, and I guess, to some extent, my mood.
> >
> > I think what git needs is something brand new that brings the two
> > together and has all of the advantages of both approaches. Let me
> > explain what I've got in mind...
> >
> > I've been calling this proposal `git replay` or `git replace` but I'd
> > like to hear other suggestions for what to name it. It works like
> > rebase except with one very important difference. Instead of orphaning
> > the original commit, it keeps a pointer to it in the commit just like
> > a `parent` entry but calls it `replaces` instead to distinguish it
> > from regular history. In the resulting commit history, following
> > `parent` pointers shows exactly the same history as if the commit had
> > been rebased. Meanwhile, the history of iterating on the change itself
> > is available by following `replaces` pointers. The new commit replaces
> > the old one but keeps it around to record how the change evolved.
> >
> > The git history now has two dimensions. The first shows a cleaned up
> > history where fix ups and code review feedback have been rolled into
> > the original changes and changes can possibly be ordered in a nice
> > linear progression that is much easier to understand. The second
> > drills into the history of a change. There is no loss and you don't
> > change history in a way that will cause problems for others who have
> > the older commits.
> >
> > Replay handles collaboration between multiple authors on a single
> > change. This is difficult and prone to accidental loss when using
> > rebase and it results in a complex history when done with merge. With
> > replay, collaborators could merge while collaborating on a single
> > change and a record of each one's contributions can be preserved.
> > Attempting this level of collaboration caused me many headaches when I
> > worked with the gerrit workflow (which in many ways, I like a lot).
> >
> > I blogged about this proposal earlier this year when I first thought
> > of it [1]. I got busy and didn't think about it for a while. Now with
> > a little time off of work, I've come back to revisit it. The blog
> > entry has a few examples showing how it works and how the history will
> > look in a few examples. Take a look.
> >
> > Various git commands will have to learn how to handle this kind of
> > history. For example, things like fetch, push, gc, and others that
> > move history around and clean out orphaned history should treat
> > anything reachable through `replaces` pointers as precious. Log and
> > related history commands may need new switches to traverse the history
> > differently in different situations. Bisect is a interesting one. I
> > tend to think that bisect should prefer the regular commit history but
> > have the ability to drill into the change history if necessary.
> >
> > In my opinion, this proposal would bring together rebase and merge in
> > a powerful way and could end the contention. Thanks for your
> > consideration.
> >
> > Carl Baldwin
> >
> > [1] http://blog.episodicgenius.com/post/merge-or-rebase--neither/ [2]
> > https://git-scm.com/book/en/v2/Git-Branching-Rebasing [3]
> > http://changelog.complete.org/archives/586-rebase-considered-harmful
> 
> I think this is a worthwhile thing to implement, there are certainly
> use-cases where you'd like to have your cake & eat it too as it were,
> i.e. have a nice rebased history in "git log", but also have the "raw"
> history for all the reasons the fossil people like to talk about, or for
> some compliance reasons.
> 
> But I don't see why you think this needs a new "replaces" parent pointer
> orthagonal to parent pointers, i.e. something that would need to be a
> new field in the commit object (I may have misread the proposal, it's
> not heavy on technical details).
> 
> Consider a merge use case like this:
> 
>           A---B---C topic
>          /         \
>     D---E---F---G---H master
> 
> Here we worked on a topic with commits A,B & C, maybe we regret not
> squashing B into A, but it gives us the "raw" history. Instead we might
> rebase it like this:
> 
>           A+B---C topic
>          /
>     G---H master
> 
> Now we can push "topic" to master, but as you've noted this loses the
> raw history, but now consider doing this instead:
> 
>           A---B---C   A2+B2---C2 topic
>          /         \ /
>     D---E---F---G---G master
> 
> I.e. you could have started working on commit A/B/C, now you "git
> replace" them (which would be some fancy rebase alias), and what it'll
> do is create a merge commit that entirely resolves the conflict so that
> hte tree is equivalent to what "master" was already at. Then you rewrite
> them and re-apply them on top.

1) you just described the "merging rebase" I use in Git for Windows for
*quite* a while (five years or so):

https://github.com/git-for-windows/build-extra/blob/af9cff5005/shears.sh#L12-L18

Just look for commits in https://github.com/git-for-windows/git/commits
whose oneline begins with "Start the merging-rebase".

2) you do not resolve merge conflicts here, as there may not be any.
Instead, you use the "ours" merge strategy.

> If you run "git log" it will already ignore A,B,C unless you specify
> --full-history, so git already knows to ignore these sort of side
> histories that result in no changes on the branch they got merged
> into. I don't know about bisect, but if it's not doing something similar
> already it would be easy to make it do so.

Sadly, it is not as easy as that. When you call "git log", you often want
to know *when* a change was introduced originally. In this case, you would
*not* want A, B nor C ignored, but you would really want to dig into that
history that is ignored by default.

In general, the technique you described (and that I described years before
you, and employ for years, too, so I actually already have experience with
its pros and cons) works, but leaves quite a bit to be desired.

For example, when anybody asks me "when was XYZ fixed in Git for Windows?"
it is not enough to run `git blame` and then `git name-rev` on the commit
identified by `git blame`: this would be your A2, and there could be any
number of previous iterations *of the same patch*. What I do in this case
is to search for the matching oneline in the full history, from the end.
This is a costly, and not very automatable operation (as there have been
rewordings at times, in particular when the oneline contained a typo).

> You could even add a new field to the commit object of A2+B2 & C2 which
> would be one or more of "replaces <sha1 of A/B/C>", commit objects
> support adding arbitrary new fields without anything breaking.

This is a very fragile way of doing things because you cannot fix rebases
done in the past. Those commits won't have that header, and you cannot put
it there after the fact, not even manually identifying the mapping.

Besides, there are plenty of scenarios when you do not actually want a
merging-rebase, e.g. when you develop a patch series and have to iterate
it over a dozen times until it is finally accepted into core Git. In this
instance, you may want to retain the iterations' commit histories during
the time of the development, but you probably won't need it any longer
after the patches have been integrated into a released version.

Baking those names into the commit object would kind of cause broken links
in such a scenario.

BTW it gets a lot more complicated when you think about

1) fixups and squashes, and

2) the often much more interesting question: *with what commit* was this
one replaced?

> But most importantly, while I think this gives you the same things from
> a UX level, it doesn't need any changes to fetch, push, gc or whatever,
> since it's all stuff we support today, someone just needs to hack
> "rebase" to create this sort of no-op merge commit to take advantage of
> it.

I already did that. You can use the above-linked shears.sh script to
perform such a merging-rebase.

However, my experience is that the lack of UX in Git's tools do hurt at
times, it is incorrect to say that log or blame already support this use
case (see the discussion above).

The most important part would be to record the mapping between old and new
commits; the `post-rewrite` hook would pose a natural way to implement
this: it gets called after a successful rebase, receiving a stream of
lines via stdin of the form `<old-commit> <new-commit>` (listing multiple
lines for the same <new-commit> if there were fixups and/or squashes).

This points to another command that absolutely would need patching: `git
pull` (or more correctly: `git merge`). Why, you ask? If you use that
technique (and we do, as I pointed out earlier, in Git for Windows),
contributors *will* start to send you contributions *based on previous
iterations*. If you integrate them ("pull"), the merge may very well
succeed. But the next time you rebase, those commits will not be ordered
correctly, as they are considered older than the patches on which they are
based (which have been rebased in the meantime already).

In Git for Windows, I do have these problems, and they are even worse
there because instead of a linearizing rebase, I recreate the branch
structure instead (see https://github.com/git/git/pull/447 for my upcoming
attempt to implement this functionality directly in core Git, in proper,
performant and portable C). So the base commits are *really* important
information. And I had to work harder in the past to find out what the
newer iteration of the base commit really is.

BTW I would *strongly* suggest to use notes instead of a new commit
header. You absolutely do not want to impose this on any user who does not
want it. And notes can be added for already-completed rebases. Even
manually, if need be.

Ciao,
Johannes

^ permalink raw reply	[relevance 0%]

* Re: Bring together merge and rebase
  2017-12-23  6:10  3% Bring together merge and rebase Carl Baldwin
@ 2017-12-23 18:59  0% ` Ævar Arnfjörð Bjarmason
  2017-12-23 22:30  0%   ` Johannes Schindelin
  2017-12-25  3:52  0% ` Theodore Ts'o
  2017-12-26  4:08  0% ` Mike Hommey
  2 siblings, 1 reply; 200+ results
From: Ævar Arnfjörð Bjarmason @ 2017-12-23 18:59 UTC (permalink / raw)
  To: Carl Baldwin; +Cc: Git Mailing List


On Sat, Dec 23 2017, Carl Baldwin jotted:

> The big contention among git users is whether to rebase or to merge
> changes [2][3] while iterating. I used to firmly believe that merging
> was the way to go and rebase was harmful. More recently, I have worked
> in some environments where I saw rebase used very effectively while
> iterating on changes and I relaxed my stance a lot. Now, I'm on the
> fence. I appreciate the strengths and weaknesses of both approaches. I
> waffle between the two depending on the situation, the tools being
> used, and I guess, to some extent, my mood.
>
> I think what git needs is something brand new that brings the two
> together and has all of the advantages of both approaches. Let me
> explain what I've got in mind...
>
> I've been calling this proposal `git replay` or `git replace` but I'd
> like to hear other suggestions for what to name it. It works like
> rebase except with one very important difference. Instead of orphaning
> the original commit, it keeps a pointer to it in the commit just like
> a `parent` entry but calls it `replaces` instead to distinguish it
> from regular history. In the resulting commit history, following
> `parent` pointers shows exactly the same history as if the commit had
> been rebased. Meanwhile, the history of iterating on the change itself
> is available by following `replaces` pointers. The new commit replaces
> the old one but keeps it around to record how the change evolved.
>
> The git history now has two dimensions. The first shows a cleaned up
> history where fix ups and code review feedback have been rolled into
> the original changes and changes can possibly be ordered in a nice
> linear progression that is much easier to understand. The second
> drills into the history of a change. There is no loss and you don't
> change history in a way that will cause problems for others who have
> the older commits.
>
> Replay handles collaboration between multiple authors on a single
> change. This is difficult and prone to accidental loss when using
> rebase and it results in a complex history when done with merge. With
> replay, collaborators could merge while collaborating on a single
> change and a record of each one's contributions can be preserved.
> Attempting this level of collaboration caused me many headaches when I
> worked with the gerrit workflow (which in many ways, I like a lot).
>
> I blogged about this proposal earlier this year when I first thought
> of it [1]. I got busy and didn't think about it for a while. Now with
> a little time off of work, I've come back to revisit it. The blog
> entry has a few examples showing how it works and how the history will
> look in a few examples. Take a look.
>
> Various git commands will have to learn how to handle this kind of
> history. For example, things like fetch, push, gc, and others that
> move history around and clean out orphaned history should treat
> anything reachable through `replaces` pointers as precious. Log and
> related history commands may need new switches to traverse the history
> differently in different situations. Bisect is a interesting one. I
> tend to think that bisect should prefer the regular commit history but
> have the ability to drill into the change history if necessary.
>
> In my opinion, this proposal would bring together rebase and merge in
> a powerful way and could end the contention. Thanks for your
> consideration.
>
> Carl Baldwin
>
> [1] http://blog.episodicgenius.com/post/merge-or-rebase--neither/
> [2] https://git-scm.com/book/en/v2/Git-Branching-Rebasing
> [3] http://changelog.complete.org/archives/586-rebase-considered-harmful

I think this is a worthwhile thing to implement, there are certainly
use-cases where you'd like to have your cake & eat it too as it were,
i.e. have a nice rebased history in "git log", but also have the "raw"
history for all the reasons the fossil people like to talk about, or for
some compliance reasons.

But I don't see why you think this needs a new "replaces" parent pointer
orthagonal to parent pointers, i.e. something that would need to be a
new field in the commit object (I may have misread the proposal, it's
not heavy on technical details).

Consider a merge use case like this:

          A---B---C topic
         /         \
    D---E---F---G---H master

Here we worked on a topic with commits A,B & C, maybe we regret not
squashing B into A, but it gives us the "raw" history. Instead we might
rebase it like this:

          A+B---C topic
         /
    G---H master

Now we can push "topic" to master, but as you've noted this loses the
raw history, but now consider doing this instead:

          A---B---C   A2+B2---C2 topic
         /         \ /
    D---E---F---G---G master

I.e. you could have started working on commit A/B/C, now you "git
replace" them (which would be some fancy rebase alias), and what it'll
do is create a merge commit that entirely resolves the conflict so that
hte tree is equivalent to what "master" was already at. Then you rewrite
them and re-apply them on top.

If you run "git log" it will already ignore A,B,C unless you specify
--full-history, so git already knows to ignore these sort of side
histories that result in no changes on the branch they got merged
into. I don't know about bisect, but if it's not doing something similar
already it would be easy to make it do so.

You could even add a new field to the commit object of A2+B2 & C2 which
would be one or more of "replaces <sha1 of A/B/C>", commit objects
support adding arbitrary new fields without anything breaking.

But most importantly, while I think this gives you the same things from
a UX level, it doesn't need any changes to fetch, push, gc or whatever,
since it's all stuff we support today, someone just needs to hack
"rebase" to create this sort of no-op merge commit to take advantage of
it.

^ permalink raw reply	[relevance 0%]

* Bring together merge and rebase
@ 2017-12-23  6:10  3% Carl Baldwin
  2017-12-23 18:59  0% ` Ævar Arnfjörð Bjarmason
                   ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Carl Baldwin @ 2017-12-23  6:10 UTC (permalink / raw)
  To: Git Mailing List

The big contention among git users is whether to rebase or to merge
changes [2][3] while iterating. I used to firmly believe that merging
was the way to go and rebase was harmful. More recently, I have worked
in some environments where I saw rebase used very effectively while
iterating on changes and I relaxed my stance a lot. Now, I'm on the
fence. I appreciate the strengths and weaknesses of both approaches. I
waffle between the two depending on the situation, the tools being
used, and I guess, to some extent, my mood.

I think what git needs is something brand new that brings the two
together and has all of the advantages of both approaches. Let me
explain what I've got in mind...

I've been calling this proposal `git replay` or `git replace` but I'd
like to hear other suggestions for what to name it. It works like
rebase except with one very important difference. Instead of orphaning
the original commit, it keeps a pointer to it in the commit just like
a `parent` entry but calls it `replaces` instead to distinguish it
from regular history. In the resulting commit history, following
`parent` pointers shows exactly the same history as if the commit had
been rebased. Meanwhile, the history of iterating on the change itself
is available by following `replaces` pointers. The new commit replaces
the old one but keeps it around to record how the change evolved.

The git history now has two dimensions. The first shows a cleaned up
history where fix ups and code review feedback have been rolled into
the original changes and changes can possibly be ordered in a nice
linear progression that is much easier to understand. The second
drills into the history of a change. There is no loss and you don't
change history in a way that will cause problems for others who have
the older commits.

Replay handles collaboration between multiple authors on a single
change. This is difficult and prone to accidental loss when using
rebase and it results in a complex history when done with merge. With
replay, collaborators could merge while collaborating on a single
change and a record of each one's contributions can be preserved.
Attempting this level of collaboration caused me many headaches when I
worked with the gerrit workflow (which in many ways, I like a lot).

I blogged about this proposal earlier this year when I first thought
of it [1]. I got busy and didn't think about it for a while. Now with
a little time off of work, I've come back to revisit it. The blog
entry has a few examples showing how it works and how the history will
look in a few examples. Take a look.

Various git commands will have to learn how to handle this kind of
history. For example, things like fetch, push, gc, and others that
move history around and clean out orphaned history should treat
anything reachable through `replaces` pointers as precious. Log and
related history commands may need new switches to traverse the history
differently in different situations. Bisect is a interesting one. I
tend to think that bisect should prefer the regular commit history but
have the ability to drill into the change history if necessary.

In my opinion, this proposal would bring together rebase and merge in
a powerful way and could end the contention. Thanks for your
consideration.

Carl Baldwin

[1] http://blog.episodicgenius.com/post/merge-or-rebase--neither/
[2] https://git-scm.com/book/en/v2/Git-Branching-Rebasing
[3] http://changelog.complete.org/archives/586-rebase-considered-harmful

^ permalink raw reply	[relevance 3%]

* Re: How hard would it be to implement sparse fetching/pulling?
  2017-12-04 15:36  0%                 ` Jeff Hostetler
@ 2017-12-05 23:46  0%                   ` Philip Oakley
  0 siblings, 0 replies; 200+ results
From: Philip Oakley @ 2017-12-05 23:46 UTC (permalink / raw)
  To: Vitaly Arbuzov, Jeff Hostetler; +Cc: Git List

From: "Jeff Hostetler" <git@jeffhostetler.com>
Sent: Monday, December 04, 2017 3:36 PM
>
> On 12/2/2017 11:30 AM, Philip Oakley wrote:
>> From: "Jeff Hostetler" <git@jeffhostetler.com>
>> Sent: Friday, December 01, 2017 2:30 PM
>>> On 11/30/2017 8:51 PM, Vitaly Arbuzov wrote:
>>>> I think it would be great if we high level agree on desired user
>>>> experience, so let me put a few possible use cases here.
>>>>
>>>> 1. Init and fetch into a new repo with a sparse list.
>>>> Preconditions: origin blah exists and has a lot of folders inside of
>>>> src including "bar".
>>>> Actions:
>>>> git init foo && cd foo
>>>> git config core.sparseAll true # New flag to activate all sparse
>>>> operations by default so you don't need to pass options to each
>>>> command.
>>>> echo "src/bar" > .git/info/sparse-checkout
>>>> git remote add origin blah
>>>> git pull origin master
>>>> Expected results: foo contains src/bar folder and nothing else,
>>>> objects that are unrelated to this tree are not fetched.
>>>> Notes: This should work same when fetch/merge/checkout operations are
>>>> used in the right order.
>>>
>>> With the current patches (parts 1,2,3) we can pass a blob-ish
>>> to the server during a clone that refers to a sparse-checkout
>>> specification.
>>
>> I hadn't appreciated this capability. I see it as important, and should 
>> be available both ways, so that a .gitNarrow spec can be imposed from the 
>> server side, as well as by the requester.
>>
>> It could also be used to assist in the 'precious/secret' blob problem, so 
>> that AWS keys are never pushed, nor available for fetching!
>
> To be honest, I've always considered partial clone/fetch as
> a client-side request as a performance feature to minimize
> download times and disk space requirements on the client.

Mine was a two way view where one side or other specified an extent for the 
narrow clone to achieve either the speed/space improvement or partitioning 
capability.

> I've not thought of it from the "server has secrets" point
> of view.

My potential for "secrets" was a little softer that some of the 'hard' 
security that is often discussed. I'm for the layered risk approach (swiss 
cheese model)
>
> We can talk about it, but I'd like to keep it outside the
> scope of the current effort.

Agreed.

>  My concerns are that that is
> not the appropriate mechanism to enforce MAC/DAC like security
> mechanisms.  For example:
> [a] The client will still receive the containing trees that
>     refer to the sensitive blobs, so the user can tell when
>     the secret blobs change -- they wouldn't have either blob,
>     but can tell when they are changed.  This event by itself
>     may or may not leak sensitive information depending on the
>     terms of the security policy in place.
> [b] The existence of such missing blobs would tell the client
>     which blobs are significant and secret and allow them to
>     focus their attack.  It would be better if those assets
>     were completely hidden and not in the tree at all.
> [c] The client could push a fake secret blob to replace the
>     valid one on the server.  You would have to audit the
>     server to ensure that it never accepts a push containing
>     a change to any secret blob.  And the server would need
>     an infrastructure to know about all secrets in the tree.
> [d] When a secret blob does change, any local merges by the
>     user lack information to complete the merge -- they can't
>     merge the secrets and they can't be trusted to correctly
>     pick-ours or pick-theirs -- so their workflows are broken.
> I'm not trying to blindly spread FUD here, but it is arguments
> like these that make me suggest that the partial clone mechanism
> is not the right vehicle for such "secret" blobs.

I'm on the 'a little security is better than no security' side, but all the 
points are valid.
>
>
>>
>>> There's a bit of a chicken-n-egg problem getting
>>> things set up. So if we assume your team would create a series
>>> of "known enlistments" under version control, then you could
>>
>> s/enlistments/entitlements/ I presume?
>
> Within my org we speak of "enlistments" as subset of the tree
> that you plan to work on.  For example, you might enlist in the
> "file system" portion of the tree or in the "device drivers"
> portion.  If the Makefiles have good partitioning, you should
> only need one of the above portions to do productive work within
> a feature area.
Ah, so it's the things that have been requested by the client (I'd like to 
the enlist..)

>
> I'm not sure what you mean by "entitlements".

It is like having the title deeds to a house - a list things you have, or 
can have. (e.g. a father saying: you can have the car on Saturday 6pm -11pm)

At the end of the day the particular lists would be the same, they guide 
what is sent.

>
>>
>>> just reference one by <branch>:<path> during your clone. The
>>> server can lookup that blob and just use it.
>>>
>>> git clone --filter=sparse:oid=master:templates/bar URL
>>>
>>> And then the server will filter-out the unwanted blobs during
>>> the clone. (The current version only filters blobs; you still
>>> get full commits and trees. That will be revisited later.)
>>
>> I'm for the idea that only the in-heirachy trees should be sent.
>> It should also be possible that the server replies that it is only 
>> sending a narrow clone, with the given (accessible?) spec.
>
> I do want to extend this to have unneeded tree filtering too.
> It is just not in this version.

Great. That's good to hear.

>
>>
>>>
>>> On the client side, the partial clone installs local config
>>> settings into the repo so that subsequent fetches default to
>>> the same filter criteria as used in the clone.
>>>
>>>
>>> I don't currently have provision to send a full sparse-checkout
>>> specification to the server during a clone or fetch. That
>>> seemed like too much to try to squeeze into the protocols.
>>> We can revisit this later if there is interest, but it wasn't
>>> critical for the initial phase.
>>>
>> Agreed. I think it should be somewhere 'visible' to the user, but could 
>> be setup by the server admin / repo maintainer if they don't have write 
>> access. But there could still be the catch-22 - maybe one starts with a 
>> <commit | toptree> : <tree> pair to define an origin point (it's not as 
>> refined as a .gitNarrow spec file, but is definative). The toptree option 
>> could even allow sub-tree clones.. maybe..
>
> That's why I suggest having the sparse-checkout specifications
> be stored under version control in the tree in a known location.
> The user could be told out-of-band that "master:enlistments/*"
> contains all of the well-defined enlistment specs -- I'm not
> proposing such an area, just that a sysadmin could agree to
> layout their tree with one.  Perhaps they have an enlistment
> that just includes that directory.  Then the user could clone
> that and look thru it -- add a new one if they need to and push
> it -- and then do a partial fetch using a different enlistment
> spec.  Again, I'm not dictating this mechanism, but just saying
> that something like the above is possible.

Ideal.

>
>>
>>>
>>>>
>>>> 2. Add a file and push changes.
>>>> Preconditions: all steps above followed.
>>>> touch src/bar/baz.txt && git add -A && git commit -m "added a file"
>>>> git push origin master
>>>> Expected results: changes are pushed to remote.
>>>
>>> I don't believe partial clone and/or partial fetch will cause
>>> any changes for push.
>>
>> I suspect that pushes could be rejected if the user 'pretends'
>> to modify files or trees outside their area. It does need the
>> user to be able to spoof part of a tree they don't have, so an
>> upstream / remote would immediatly know it was a spoof but
>> locally the narrow clone doesn't have enough detail about the
>> 'bad' oid. It would be right to reject such attempts!
>
> There is nothing in the partial clone/fetch to support this.
> The server doesn't know which parts of the tree the user has
> or doesn't have.  There is nothing to prevent the user from
> creating a new file anywhere in the tree -- even if they don't
> have blobs for anything else in the surrounding directory --
> and including it in a push -- since the local "git commit"
> would see it as adding a single file with a new SHA and
> use the existing SHAs for the neighboring files.
>

OK. That's something I'll have a think about.

I was thinking that the recieving server would cross check the recieved 
trees against the enlistments/entitlements to confirm that the user hasn't 
suggested that they have a blob/tree that neither know about (at least for a 
server that has that requirement to do the check!). This is something 
Randall also brought up in his thread.

>
>>
>>>
>>>>
>>>> 3. Clone a repo with a sparse list as a filter.
>>>> Preconditions: same as for #1
>>>> Actions:
>>>> echo "src/bar" > /tmp/blah-sparse-checkout
>>>> git clone --sparse /tmp/blah-sparse-checkout blah # Clone should be
>>>> the only command that would requires specific option key being passed.
>>>> Expected results: same as for #1 plus /tmp/blah-sparse-checkout is
>>>> copied into .git/info/sparse-checkout
>>
>> I presume clone and fetch are treated equivalently here.
>
> Yes, for the download and config setup, both clone and fetch are
> equivalent.  They can pass a filter-spec to the server and set
> the local config variables to indicate that a partial clone/fetch
> was used.

Good.
>
>>
>>>
>>> There are 2 independent concepts here: clone and checkout.
>>> Currently, there isn't any automatic linkage of the partial clone to
>>> the sparse-checkout settings, so you could do something like this:
>>>
>> I see an implicit link that clearly one cannot checkout
>> (inflate/populate) a file/directory that one does not have
>> in the object store. But that does not imply the reverse linkage.
>> The regular sparse checkout should be available independently of
>> the local clone being a narrow one.
>
> Right, I wasn't talking about changing sparse-checkout.  I was
> just pointing out that after you complete a partial-clone, you
> need to take a few steps before you can do a checkout that wont'
> complain about the missing blobs -- or worse, demand load all
> of them.
>

OK.
>
>>
>>> git clone --no-checkout --filter=sparse:oid=master:templates/bar URL
>>> git cat-file ... templates/bar >.git/info/sparse-checkout
>>> git config core.sparsecheckout true
>>> git checkout ...
>>>
>>> I've been focused on the clone/fetch issues and have not looked
>>> into the automation to couple them.
>>>
>>
>> I foresee that large files and certain files need to be filterable
>> for fetch-clone, and that might not be (backward) compatible
>> with the sparse-checkout.
>
> There are several filter-spec criteria: no-blobs, no-large-blobs,
> sparse-checkout-compatible and others may be added later.  Each
> may require different post-clone or post-fetch handling.
>
> For example, you may want to configure your client to only omit
> large blobs and configure a "missing blob helper" (outside of my
> scope) that fetches them from S3 rather than from the origin
> remote.  This would not need to use sparse-checkout.
>
> I guess what I'm trying to say is that this effort is providing
> a mechanism to let the git client request object filtering and
> work with missing objects locally.

OK.
>
>>
>>>
>>>>
>>>> 4. Showing log for sparsely cloned repo.
>>>> Preconditions: #3 is followed
>>>> Actions:
>>>> git log
>>>> Expected results: recent changes that affect src/bar tree.
>>>
>>> If I understand your meaning, log would only show changes
>>> within the sparse subset of the tree. This is not on my
>>> radar for partial clone/fetch. It would be a nice feature
>>> to have, but I think it would be better to think about it
>>> from the point of view of sparse-checkout rather than clone.
>>>
>> One option maybe by making a marker for the tree/blob to
>> be a first class citizen. So the oid (and worktree file)
>> has content ".gitNarrowTree <oid>" or ",gitNarrowBlob <oid>"
>> as required (*), which is safe, and allows a consistent
>> alter-ego view of the tree contents and hence for git-log et.al.
>>
>> (*) I keep flip flopping between a single object marker, and
>> distinct object markers for the types. It partly depends on
>> whether one can know in advance, locally, what the oid type
>> should be, and how it should be embedded in the object store
>> - need to re-check the specs.
>>
>> I'm tending toward distinct types to cope with the D/F conflict
>> in the worktrees - the directory must be created (holds the
>> name etc), and the alter-ego content then must be placed in a
>> _known_ sub-file ".gitNarrowTree" (without the oid in the file
>> name, but included in the content). Presence of a ".gitNarrowTree"
>> should be standalone in the directory when that part of the
>> work-tree is clean.
>
> I'm not sure I follow this, but it is outside of my scope
> for partial clone/fetch, so I'd rather not dive too deep on
> this here.  If we really want a version of "git log" that
> respects sparse-checkout boundaries, we should start a new
> thread.  Thanks.
>

Agreed.

>>
>>>
>>>>
>>>> 5. Showing diff.
>>>> Preconditions: #3 is followed
>>>> Actions:
>>>> git diff HEAD^ HEAD
>>>> Expected results: changes from the most recent commit affecting
>>>> src/bar folder are shown.
>>>> Notes: this can be tricky operation as filtering must be done to
>>>> remove results from unrelated subtrees.
>>>
>>> I don't have any plan for this and I don't think it fits within
>>> the scope of clone/fetch. I think this too would be a sparse-checkout
>>> feature.
>>>
>>
>> See my note about first class citizens for marker OIDs
>>
>>>
>>>>
>>>> *Note that I intentionally didn't mention use cases that are related
>>>> to filtering by blob size as I think we should logically consider them
>>>> as a separate, although related, feature.
>>>
>>> I've grouped blob-size and sparse filter together for the
>>> purposes of clone/fetch since the basic mechanisms (filtering,
>>> transport, and missing object handling) are the same for both.
>>> They do lead to different end-uses, but that is above my level
>>> here.
>>>
>>>
>>>>
>>>> What do you think about these examples above? Is that something that
>>>> more-or-less fits into current development? Are there other important
>>>> flows that I've missed?
>>>
>>> These are all good ideas and it is good to have someone else who
>>> wants to use partial+sparse thinking about it and looking for gaps
>>> as we try to make a complete end-to-end feature.
>>>>
>>>> -Vitaly
>>>
>>> Thanks
>>> Jeff
>>>
>>
>> Philip
>>
>
> Thanks!
> Jeff
>
--
Philip 


^ permalink raw reply	[relevance 0%]

* Re: How hard would it be to implement sparse fetching/pulling?
  2017-12-02 16:30  3%               ` Philip Oakley
@ 2017-12-04 15:36  0%                 ` Jeff Hostetler
  2017-12-05 23:46  0%                   ` Philip Oakley
  0 siblings, 1 reply; 200+ results
From: Jeff Hostetler @ 2017-12-04 15:36 UTC (permalink / raw)
  To: Philip Oakley, Vitaly Arbuzov; +Cc: Git List



On 12/2/2017 11:30 AM, Philip Oakley wrote:
> From: "Jeff Hostetler" <git@jeffhostetler.com>
> Sent: Friday, December 01, 2017 2:30 PM
>> On 11/30/2017 8:51 PM, Vitaly Arbuzov wrote:
>>> I think it would be great if we high level agree on desired user
>>> experience, so let me put a few possible use cases here.
>>>
>>> 1. Init and fetch into a new repo with a sparse list.
>>> Preconditions: origin blah exists and has a lot of folders inside of
>>> src including "bar".
>>> Actions:
>>> git init foo && cd foo
>>> git config core.sparseAll true # New flag to activate all sparse
>>> operations by default so you don't need to pass options to each
>>> command.
>>> echo "src/bar" > .git/info/sparse-checkout
>>> git remote add origin blah
>>> git pull origin master
>>> Expected results: foo contains src/bar folder and nothing else,
>>> objects that are unrelated to this tree are not fetched.
>>> Notes: This should work same when fetch/merge/checkout operations are
>>> used in the right order.
>>
>> With the current patches (parts 1,2,3) we can pass a blob-ish
>> to the server during a clone that refers to a sparse-checkout
>> specification.
> 
> I hadn't appreciated this capability. I see it as important, and should be available both ways, so that a .gitNarrow spec can be imposed from the server side, as well as by the requester.
> 
> It could also be used to assist in the 'precious/secret' blob problem, so that AWS keys are never pushed, nor available for fetching!

To be honest, I've always considered partial clone/fetch as
a client-side request as a performance feature to minimize
download times and disk space requirements on the client.
I've not thought of it from the "server has secrets" point
of view.

We can talk about it, but I'd like to keep it outside the
scope of the current effort.  My concerns are that that is
not the appropriate mechanism to enforce MAC/DAC like security
mechanisms.  For example:
[a] The client will still receive the containing trees that
     refer to the sensitive blobs, so the user can tell when
     the secret blobs change -- they wouldn't have either blob,
     but can tell when they are changed.  This event by itself
     may or may not leak sensitive information depending on the
     terms of the security policy in place.
[b] The existence of such missing blobs would tell the client
     which blobs are significant and secret and allow them to
     focus their attack.  It would be better if those assets
     were completely hidden and not in the tree at all.
[c] The client could push a fake secret blob to replace the
     valid one on the server.  You would have to audit the
     server to ensure that it never accepts a push containing
     a change to any secret blob.  And the server would need
     an infrastructure to know about all secrets in the tree.
[d] When a secret blob does change, any local merges by the
     user lack information to complete the merge -- they can't
     merge the secrets and they can't be trusted to correctly
     pick-ours or pick-theirs -- so their workflows are broken.
I'm not trying to blindly spread FUD here, but it is arguments
like these that make me suggest that the partial clone mechanism
is not the right vehicle for such "secret" blobs.


> 
>>        There's a bit of a chicken-n-egg problem getting
>> things set up.  So if we assume your team would create a series
>> of "known enlistments" under version control, then you could
> 
> s/enlistments/entitlements/ I presume?

Within my org we speak of "enlistments" as subset of the tree
that you plan to work on.  For example, you might enlist in the
"file system" portion of the tree or in the "device drivers"
portion.  If the Makefiles have good partitioning, you should
only need one of the above portions to do productive work within
a feature area.

I'm not sure what you mean by "entitlements".

> 
>> just reference one by <branch>:<path> during your clone.  The
>> server can lookup that blob and just use it.
>>
>>     git clone --filter=sparse:oid=master:templates/bar URL
>>
>> And then the server will filter-out the unwanted blobs during
>> the clone.  (The current version only filters blobs; you still
>> get full commits and trees.  That will be revisited later.)
> 
> I'm for the idea that only the in-heirachy trees should be sent.
> It should also be possible that the server replies that it is 
> only sending a narrow clone, with the given (accessible?) spec.

I do want to extend this to have unneeded tree filtering too.
It is just not in this version.

> 
>>
>> On the client side, the partial clone installs local config
>> settings into the repo so that subsequent fetches default to
>> the same filter criteria as used in the clone.
>>
>>
>> I don't currently have provision to send a full sparse-checkout
>> specification to the server during a clone or fetch.  That
>> seemed like too much to try to squeeze into the protocols.
>> We can revisit this later if there is interest, but it wasn't
>> critical for the initial phase.
>>
> Agreed. I think it should be somewhere 'visible' to the user, but could be setup by the server admin / repo maintainer if they don't have write access. But there could still be the catch-22 - maybe one starts with a <commit | toptree> : <tree> pair to define an origin point (it's not as refined as a .gitNarrow spec file, but is definative). The toptree option could even allow sub-tree clones.. maybe..

That's why I suggest having the sparse-checkout specifications
be stored under version control in the tree in a known location.
The user could be told out-of-band that "master:enlistments/*"
contains all of the well-defined enlistment specs -- I'm not
proposing such an area, just that a sysadmin could agree to
layout their tree with one.  Perhaps they have an enlistment
that just includes that directory.  Then the user could clone
that and look thru it -- add a new one if they need to and push
it -- and then do a partial fetch using a different enlistment
spec.  Again, I'm not dictating this mechanism, but just saying
that something like the above is possible.

> 
>>
>>>
>>> 2. Add a file and push changes.
>>> Preconditions: all steps above followed.
>>> touch src/bar/baz.txt && git add -A && git commit -m "added a file"
>>> git push origin master
>>> Expected results: changes are pushed to remote.
>>
>> I don't believe partial clone and/or partial fetch will cause
>> any changes for push.
> 
> I suspect that pushes could be rejected if the user 'pretends'
> to modify files or trees outside their area. It does need the
> user to be able to spoof part of a tree they don't have, so an
> upstream / remote would immediatly know it was a spoof but
> locally the narrow clone doesn't have enough detail about the
> 'bad' oid. It would be right to reject such attempts!

There is nothing in the partial clone/fetch to support this.
The server doesn't know which parts of the tree the user has
or doesn't have.  There is nothing to prevent the user from
creating a new file anywhere in the tree -- even if they don't
have blobs for anything else in the surrounding directory --
and including it in a push -- since the local "git commit"
would see it as adding a single file with a new SHA and
use the existing SHAs for the neighboring files.


> 
>>
>>>
>>> 3. Clone a repo with a sparse list as a filter.
>>> Preconditions: same as for #1
>>> Actions:
>>> echo "src/bar" > /tmp/blah-sparse-checkout
>>> git clone --sparse /tmp/blah-sparse-checkout blah # Clone should be
>>> the only command that would requires specific option key being passed.
>>> Expected results: same as for #1 plus /tmp/blah-sparse-checkout is
>>> copied into .git/info/sparse-checkout
> 
> I presume clone and fetch are treated equivalently here.

Yes, for the download and config setup, both clone and fetch are
equivalent.  They can pass a filter-spec to the server and set
the local config variables to indicate that a partial clone/fetch
was used.

> 
>>
>> There are 2 independent concepts here: clone and checkout.
>> Currently, there isn't any automatic linkage of the partial clone to
>> the sparse-checkout settings, so you could do something like this:
>>
> I see an implicit link that clearly one cannot checkout
> (inflate/populate) a file/directory that one does not have
> in the object store. But that does not imply the reverse linkage.
> The regular sparse checkout should be available independently of
> the local clone being a narrow one.

Right, I wasn't talking about changing sparse-checkout.  I was
just pointing out that after you complete a partial-clone, you
need to take a few steps before you can do a checkout that wont'
complain about the missing blobs -- or worse, demand load all
of them.


> 
>>     git clone --no-checkout --filter=sparse:oid=master:templates/bar URL
>>     git cat-file ... templates/bar >.git/info/sparse-checkout
>>     git config core.sparsecheckout true
>>     git checkout ...
>>
>> I've been focused on the clone/fetch issues and have not looked
>> into the automation to couple them.
>>
> 
> I foresee that large files and certain files need to be filterable
> for fetch-clone, and that might not be (backward) compatible
> with the sparse-checkout.

There are several filter-spec criteria: no-blobs, no-large-blobs,
sparse-checkout-compatible and others may be added later.  Each
may require different post-clone or post-fetch handling.

For example, you may want to configure your client to only omit
large blobs and configure a "missing blob helper" (outside of my
scope) that fetches them from S3 rather than from the origin
remote.  This would not need to use sparse-checkout.

I guess what I'm trying to say is that this effort is providing
a mechanism to let the git client request object filtering and
work with missing objects locally.

> 
>>
>>>
>>> 4. Showing log for sparsely cloned repo.
>>> Preconditions: #3 is followed
>>> Actions:
>>> git log
>>> Expected results: recent changes that affect src/bar tree.
>>
>> If I understand your meaning, log would only show changes
>> within the sparse subset of the tree.  This is not on my
>> radar for partial clone/fetch.  It would be a nice feature
>> to have, but I think it would be better to think about it
>> from the point of view of sparse-checkout rather than clone.
>>
> One option maybe by making a marker for the tree/blob to
> be a first class citizen. So the oid (and worktree file)
> has content ".gitNarrowTree <oid>" or ",gitNarrowBlob <oid>"
> as required (*), which is safe, and allows a consistent
> alter-ego view of the tree contents and hence for git-log et.al.
> 
> (*) I keep flip flopping between a single object marker, and
> distinct object markers for the types. It partly depends on
> whether one can know in advance, locally, what the oid type
> should be, and how it should be embedded in the object store
> - need to re-check the specs.
> 
> I'm tending toward distinct types to cope with the D/F conflict
> in the worktrees - the directory must be created (holds the
> name etc), and the alter-ego content then must be placed in a
> _known_ sub-file ".gitNarrowTree" (without the oid in the file
> name, but included in the content). Presence of a ".gitNarrowTree"
> should be standalone in the directory when that part of the
> work-tree is clean.

I'm not sure I follow this, but it is outside of my scope
for partial clone/fetch, so I'd rather not dive too deep on
this here.  If we really want a version of "git log" that
respects sparse-checkout boundaries, we should start a new
thread.  Thanks.

> 
>>
>>>
>>> 5. Showing diff.
>>> Preconditions: #3 is followed
>>> Actions:
>>> git diff HEAD^ HEAD
>>> Expected results: changes from the most recent commit affecting
>>> src/bar folder are shown.
>>> Notes: this can be tricky operation as filtering must be done to
>>> remove results from unrelated subtrees.
>>
>> I don't have any plan for this and I don't think it fits within
>> the scope of clone/fetch.  I think this too would be a sparse-checkout
>> feature.
>>
> 
> See my note about first class citizens for marker OIDs
> 
>>
>>>
>>> *Note that I intentionally didn't mention use cases that are related
>>> to filtering by blob size as I think we should logically consider them
>>> as a separate, although related, feature.
>>
>> I've grouped blob-size and sparse filter together for the
>> purposes of clone/fetch since the basic mechanisms (filtering,
>> transport, and missing object handling) are the same for both.
>> They do lead to different end-uses, but that is above my level
>> here.
>>
>>
>>>
>>> What do you think about these examples above? Is that something that
>>> more-or-less fits into current development? Are there other important
>>> flows that I've missed?
>>
>> These are all good ideas and it is good to have someone else who
>> wants to use partial+sparse thinking about it and looking for gaps
>> as we try to make a complete end-to-end feature.
>>>
>>> -Vitaly
>>
>> Thanks
>> Jeff
>>
> 
> Philip
> 

Thanks!
Jeff


^ permalink raw reply	[relevance 0%]

* Re: How hard would it be to implement sparse fetching/pulling?
  @ 2017-12-02 16:30  3%               ` Philip Oakley
  2017-12-04 15:36  0%                 ` Jeff Hostetler
  0 siblings, 1 reply; 200+ results
From: Philip Oakley @ 2017-12-02 16:30 UTC (permalink / raw)
  To: Vitaly Arbuzov, Jeff Hostetler; +Cc: Git List

From: "Jeff Hostetler" <git@jeffhostetler.com>
Sent: Friday, December 01, 2017 2:30 PM
> On 11/30/2017 8:51 PM, Vitaly Arbuzov wrote:
>> I think it would be great if we high level agree on desired user
>> experience, so let me put a few possible use cases here.
>>
>> 1. Init and fetch into a new repo with a sparse list.
>> Preconditions: origin blah exists and has a lot of folders inside of
>> src including "bar".
>> Actions:
>> git init foo && cd foo
>> git config core.sparseAll true # New flag to activate all sparse
>> operations by default so you don't need to pass options to each
>> command.
>> echo "src/bar" > .git/info/sparse-checkout
>> git remote add origin blah
>> git pull origin master
>> Expected results: foo contains src/bar folder and nothing else,
>> objects that are unrelated to this tree are not fetched.
>> Notes: This should work same when fetch/merge/checkout operations are
>> used in the right order.
>
> With the current patches (parts 1,2,3) we can pass a blob-ish
> to the server during a clone that refers to a sparse-checkout
> specification.

I hadn't appreciated this capability. I see it as important, and should be 
available both ways, so that a .gitNarrow spec can be imposed from the 
server side, as well as by the requester.

It could also be used to assist in the 'precious/secret' blob problem, so 
that AWS keys are never pushed, nor available for fetching!

>        There's a bit of a chicken-n-egg problem getting
> things set up.  So if we assume your team would create a series
> of "known enlistments" under version control, then you could

s/enlistments/entitlements/ I presume?

> just reference one by <branch>:<path> during your clone.  The
> server can lookup that blob and just use it.
>
>     git clone --filter=sparse:oid=master:templates/bar URL
>
> And then the server will filter-out the unwanted blobs during
> the clone.  (The current version only filters blobs; you still
> get full commits and trees.  That will be revisited later.)

I'm for the idea that only the in-heirachy trees should be sent.
It should also be possible that the server replies that it is only sending a 
narrow clone, with the given (accessible?) spec.

>
> On the client side, the partial clone installs local config
> settings into the repo so that subsequent fetches default to
> the same filter criteria as used in the clone.
>
>
> I don't currently have provision to send a full sparse-checkout
> specification to the server during a clone or fetch.  That
> seemed like too much to try to squeeze into the protocols.
> We can revisit this later if there is interest, but it wasn't
> critical for the initial phase.
>
Agreed. I think it should be somewhere 'visible' to the user, but could be 
setup by the server admin / repo maintainer if they don't have write access. 
But there could still be the catch-22 - maybe one starts with a <commit | 
toptree> : <tree> pair to define an origin point (it's not as refined as a 
.gitNarrow spec file, but is definative). The toptree option could even 
allow sub-tree clones.. maybe..

>
>>
>> 2. Add a file and push changes.
>> Preconditions: all steps above followed.
>> touch src/bar/baz.txt && git add -A && git commit -m "added a file"
>> git push origin master
>> Expected results: changes are pushed to remote.
>
> I don't believe partial clone and/or partial fetch will cause
> any changes for push.

I suspect that pushes could be rejected if the user 'pretends' to modify 
files or trees outside their area. It does need the user to be able to spoof 
part of a tree they don't have, so an upstream / remote would immediatly 
know it was a spoof but locally the narrow clone doesn't have enough detail 
about the 'bad' oid. It would be right to reject such attempts!

>
>>
>> 3. Clone a repo with a sparse list as a filter.
>> Preconditions: same as for #1
>> Actions:
>> echo "src/bar" > /tmp/blah-sparse-checkout
>> git clone --sparse /tmp/blah-sparse-checkout blah # Clone should be
>> the only command that would requires specific option key being passed.
>> Expected results: same as for #1 plus /tmp/blah-sparse-checkout is
>> copied into .git/info/sparse-checkout

I presume clone and fetch are treated equivalently here.

>
> There are 2 independent concepts here: clone and checkout.
> Currently, there isn't any automatic linkage of the partial clone to
> the sparse-checkout settings, so you could do something like this:
>
I see an implicit link that clearly one cannot checkout (inflate/populate) a 
file/directory that one does not have in the object store. But that does not 
imply the reverse linkage. The regular sparse checkout should be available 
independently of the local clone being a narrow one.

>     git clone --no-checkout --filter=sparse:oid=master:templates/bar URL
>     git cat-file ... templates/bar >.git/info/sparse-checkout
>     git config core.sparsecheckout true
>     git checkout ...
>
> I've been focused on the clone/fetch issues and have not looked
> into the automation to couple them.
>

I foresee that large files and certain files need to be filterable for 
fetch-clone, and that might not be (backward) compatible with the 
sparse-checkout.

>
>>
>> 4. Showing log for sparsely cloned repo.
>> Preconditions: #3 is followed
>> Actions:
>> git log
>> Expected results: recent changes that affect src/bar tree.
>
> If I understand your meaning, log would only show changes
> within the sparse subset of the tree.  This is not on my
> radar for partial clone/fetch.  It would be a nice feature
> to have, but I think it would be better to think about it
> from the point of view of sparse-checkout rather than clone.
>
One option maybe by making a marker for the tree/blob to be a first class 
citizen. So the oid (and worktree file) has content ".gitNarrowTree <oid>" 
or ",gitNarrowBlob <oid>" as required (*), which is safe, and allows a 
consistent alter-ego view of the tree contents and hence for git-log et.al.

(*) I keep flip flopping between a single object marker, and distinct object 
markers for the types. It partly depends on whether one can know in advance, 
locally, what the oid type should be, and how it should be embedded in the 
object store - need to re-check the specs.

I'm tending toward distinct types to cope with the D/F conflict in the 
worktrees - the directory must be created (holds the name etc), and the 
alter-ego content then must be placed in a _known_ sub-file ".gitNarrowTree" 
(without the oid in the file name, but included in the content). Presence of 
a ".gitNarrowTree" should be standalone in the directory when that part of 
the work-tree is clean.

>
>>
>> 5. Showing diff.
>> Preconditions: #3 is followed
>> Actions:
>> git diff HEAD^ HEAD
>> Expected results: changes from the most recent commit affecting
>> src/bar folder are shown.
>> Notes: this can be tricky operation as filtering must be done to
>> remove results from unrelated subtrees.
>
> I don't have any plan for this and I don't think it fits within
> the scope of clone/fetch.  I think this too would be a sparse-checkout
> feature.
>

See my note about first class citizens for marker OIDs

>
>>
>> *Note that I intentionally didn't mention use cases that are related
>> to filtering by blob size as I think we should logically consider them
>> as a separate, although related, feature.
>
> I've grouped blob-size and sparse filter together for the
> purposes of clone/fetch since the basic mechanisms (filtering,
> transport, and missing object handling) are the same for both.
> They do lead to different end-uses, but that is above my level
> here.
>
>
>>
>> What do you think about these examples above? Is that something that
>> more-or-less fits into current development? Are there other important
>> flows that I've missed?
>
> These are all good ideas and it is good to have someone else who
> wants to use partial+sparse thinking about it and looking for gaps
> as we try to make a complete end-to-end feature.
>>
>> -Vitaly
>
> Thanks
> Jeff
>

Philip


^ permalink raw reply	[relevance 3%]

* Re: [RFC] Indicate that Git waits for user input via editor
  @ 2017-11-15 18:37  4%     ` Stefan Beller
  0 siblings, 0 replies; 200+ results
From: Stefan Beller @ 2017-11-15 18:37 UTC (permalink / raw)
  To: Lars Schneider; +Cc: git

On Wed, Nov 15, 2017 at 10:07 AM, Lars Schneider
<larsxschneider@gmail.com> wrote:

>> Can this be put in a wrapper that opens the text editor?
>> The wrapper would print these lines and then open the text editor;
>> depending on the operating system, there might even be a command to
>> focus on that editor window.
>
> Yeah, that would be a workaround. However, in order to take these steps (write the
> wrapper, enable the focus command) the users needs to understand the problem.
> That's quite a leap especially for new Git users. They just get the feeling "Git
> is broken because it hangs".
>
> Can you imagine any downside for an "Opening editor for user input..." message?

"Wasting precious screen real estate for power users" (tm)
So maybe if one can turn it off, this would be ok? Or even for known inline
editors?

>> Regarding Git, maybe improve the documentation for how to set the editor
>> variable?
>
> The sad truth is that 98% of the users do not read the documentation
> (made up number but close to my observed reality).

Yeah that is an excellent point, but you forgot the people who
look at stackoverflow which of course links back to the docs in
the first excellent reply.

In a way this suggestion of bettering the docs was a cheap way out, sorry.

^ permalink raw reply	[relevance 4%]

* Re: SHA1 collision in production repo?! (probably not)
  @ 2017-09-12 17:38  4%       ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2017-09-12 17:38 UTC (permalink / raw)
  To: Lars Schneider; +Cc: Junio C Hamano, Git List

On Tue, Sep 12, 2017 at 06:18:32PM +0200, Lars Schneider wrote:

> we are seeing this now in Git 2.14.1:
> 
> ...
> error: inflate: data stream error (unknown compression method)
> error: unable to unpack 7b513f98a66ef9488e516e7abbc246438597c6d5 header
> error: inflate: data stream error (unknown compression method)
> error: unable to unpack 7b513f98a66ef9488e516e7abbc246438597c6d5 header
> fatal: loose object 7b513f98a66ef9488e516e7abbc246438597c6d5 (stored in .git/objects/7b/513f98a66ef9488e516e7abbc246438597c6d5) is corrupt
> fatal: The remote end hung up unexpectedly
> 
> I guess this means your fix [1] works properly :-)

Oh, good. :)

> At some point I will try to explore a retry mechanism for these cases.

I don't think we can generally retry loose-object failures. We use
copies from packs first, and then loose. So a corrupt loose can fallback
to another pack or to loose, but not the other way around (because we
would never look at the loose if we had a good copy elsewhere).

Though in your particular case, if I recall, you're receiving the object
over the network and the corrupted copy is in the way. So right now the
recovery process is:

  1. Notice the commit message.

  2. Run git-fsck to notice that we don't really[1] need the object.

  3. Run `rm .git/objects/7b/513f...`

  4. Re-run the fetch.

But in theory we should be able to say "oh, we don't _really_ have that,
the collision test isn't necessary" and then overwrite it. I actually
thought that's what would happen now (has_sha1_file() would return an
error), but I guess for what we need, it just does a stat() and calls it
a day, not realizing we ought to be overwriting.

-Peff

[1] git-fsck will actually complain if reflogs point to the object, and
    we can always expire those in a corrupted repo. So possibly what you
    want to know is whether it's reachable from actual refs. Of course
    this whole check is optional. If the object's corrupted, it's
    corrupted. But I get nervous calling `rm` on something that _could_
    be precious (say it's just a single-bit error that could be
    recovered). But if you have a known-good copy incoming, that's less
    of an issue.

^ permalink raw reply	[relevance 4%]

* Re: Undocumented change in `git branch -M` behavior
  2017-08-23 20:13  3% Undocumented change in `git branch -M` behavior Nish Aravamudan
@ 2017-08-24  5:32  0% ` Kevin Daudt
  0 siblings, 0 replies; 200+ results
From: Kevin Daudt @ 2017-08-24  5:32 UTC (permalink / raw)
  To: Nish Aravamudan; +Cc: git, gitster, Nguyễn Thái Ngọc Duy

On Wed, Aug 23, 2017 at 01:13:34PM -0700, Nish Aravamudan wrote:
> Hello,
> 
> Hopefully, I've got this right -- I noticed a change in behavior in git
> with Ubuntu 17.10, which recently got 2.14.1. Specifically, that when in
> an orphaned branch, -M ends up moving HEAD to the new branch name,
> clobbering the working tree. As far as I know, from the manpages,
> orphaned branches are still supported and should work?
> 
> I think an example will demonstrate more than words (the following are
> done in LXD containers, hence the root user):
> 
> # git --version
> git version 2.14.1
> # mkdir test && cd test && git init .
> Initialized empty Git repository in /root/test/.git/
> # git checkout -b a
> Switched to a new branch 'a'
> # touch testfile && git add testfile && git commit -m 'initial commit'
> [a (root-commit) 6061193] initial commit
>  Committer: root <root@precious-magpie.lxd>
>  1 file changed, 0 insertions(+), 0 deletions(-)
>  create mode 100644 testfile
> # git checkout --orphan master
> Switched to a new branch 'master'
> # git status
> On branch master
> 
> No commits yet
> 
> Changes to be committed:
>   (use "git rm --cached <file>..." to unstage)
> 
>         new file:   testfile
> 
> # git reset --hard && git status
> On branch master
> 
> No commits yet
> 
> nothing to commit (create/copy files and use "git add" to track)
> # git branch -M a b
> # git status
> On branch b
> Changes to be committed:
>   (use "git reset HEAD <file>..." to unstage)
> 
>         deleted:    testfile
> 
> This is very unexpected. I force-renamed a branch I wasn't currently
> checked out to and now I'm checked out to it *and* I have staged file
> removals (I think what is effectively happening is my current working
> directory (empty) is being staged into the new branch, but I'm not
> 100%).
> 
> For comparision, on 17.04:
> 
> # git --version
> git version 2.11.0
> # mkdir test && cd test && git init .
> Initialized empty Git repository in /root/test/.git/
> # git checkout -b a
> Switched to a new branch 'a'
> # touch testfile && git add testfile && git commit -m 'initial commit'
> [a (root-commit) f8d0d53] initial commit
>  Committer: root <root@honest-sturgeon.lxd>
>  1 file changed, 0 insertions(+), 0 deletions(-)
>  create mode 100644 testfile
> # git checkout --orphan master
> Switched to a new branch 'master'
> # git status
> On branch master
> 
> No commits yet
> 
> Changes to be committed:
>   (use "git rm --cached <file>..." to unstage)
> 
>         new file:   testfile
> 
> # git reset --hard && git status
> On branch master
> 
> No commits yet
> 
> nothing to commit (create/copy files and use "git add" to track)
> # git branch -M a b
> # git status
> On branch master
> 
> Initial commit
> 
> nothing to commit (create/copy files and use "git add" to track)
> 
> This is what I expect to see, the branch rename has no effect on HEAD.
> 
> I haven't yet bisected this (but I can if necessary). My initial
> suspicion is
> https://github.com/git/git/commit/70999e9ceca47e03b8900bfb310b2f804125811e#diff-d18f86ea14e2f1e5bff391b2e54438cb
> where a comparison between the oldname of the branch and HEAD was
> performed before attempting to move HEAD (so that HEAD followed to the
> new branch name, I believe). That change was dropped, though and perhaps
> the new check in replace_each_worktree_head_symref of
> 
>         strcmp(oldref, worktrees[i]->head_ref)
> 
> does not work for orphaned branches? I am unfamiliar with all the
> details of the git internals, so please correct me if I'm wrong!
> 
> Thanks,
> Nish
> 
> -- 
> Nishanth Aravamudan
> Ubuntu Server
> Canonical Ltd

Thanks for this report. I've bisected it down to 
fa099d232 (worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe(), 2017-04-24) 

I've CC'ed Duy, who made that commit.

Kevin

^ permalink raw reply	[relevance 0%]

* Undocumented change in `git branch -M` behavior
@ 2017-08-23 20:13  3% Nish Aravamudan
  2017-08-24  5:32  0% ` Kevin Daudt
  0 siblings, 1 reply; 200+ results
From: Nish Aravamudan @ 2017-08-23 20:13 UTC (permalink / raw)
  To: git; +Cc: gitster

Hello,

Hopefully, I've got this right -- I noticed a change in behavior in git
with Ubuntu 17.10, which recently got 2.14.1. Specifically, that when in
an orphaned branch, -M ends up moving HEAD to the new branch name,
clobbering the working tree. As far as I know, from the manpages,
orphaned branches are still supported and should work?

I think an example will demonstrate more than words (the following are
done in LXD containers, hence the root user):

# git --version
git version 2.14.1
# mkdir test && cd test && git init .
Initialized empty Git repository in /root/test/.git/
# git checkout -b a
Switched to a new branch 'a'
# touch testfile && git add testfile && git commit -m 'initial commit'
[a (root-commit) 6061193] initial commit
 Committer: root <root@precious-magpie.lxd>
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 testfile
# git checkout --orphan master
Switched to a new branch 'master'
# git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   testfile

# git reset --hard && git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)
# git branch -M a b
# git status
On branch b
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    testfile

This is very unexpected. I force-renamed a branch I wasn't currently
checked out to and now I'm checked out to it *and* I have staged file
removals (I think what is effectively happening is my current working
directory (empty) is being staged into the new branch, but I'm not
100%).

For comparision, on 17.04:

# git --version
git version 2.11.0
# mkdir test && cd test && git init .
Initialized empty Git repository in /root/test/.git/
# git checkout -b a
Switched to a new branch 'a'
# touch testfile && git add testfile && git commit -m 'initial commit'
[a (root-commit) f8d0d53] initial commit
 Committer: root <root@honest-sturgeon.lxd>
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 testfile
# git checkout --orphan master
Switched to a new branch 'master'
# git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   testfile

# git reset --hard && git status
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)
# git branch -M a b
# git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

This is what I expect to see, the branch rename has no effect on HEAD.

I haven't yet bisected this (but I can if necessary). My initial
suspicion is
https://github.com/git/git/commit/70999e9ceca47e03b8900bfb310b2f804125811e#diff-d18f86ea14e2f1e5bff391b2e54438cb
where a comparison between the oldname of the branch and HEAD was
performed before attempting to move HEAD (so that HEAD followed to the
new branch name, I believe). That change was dropped, though and perhaps
the new check in replace_each_worktree_head_symref of

        strcmp(oldref, worktrees[i]->head_ref)

does not work for orphaned branches? I am unfamiliar with all the
details of the git internals, so please correct me if I'm wrong!

Thanks,
Nish

-- 
Nishanth Aravamudan
Ubuntu Server
Canonical Ltd

^ permalink raw reply	[relevance 3%]

* Re: [RFC PATCH 1/4] environment, fsck: introduce lazyobject extension
  @ 2017-07-28 13:20  4%     ` Ben Peart
  0 siblings, 0 replies; 200+ results
From: Ben Peart @ 2017-07-28 13:20 UTC (permalink / raw)
  To: Junio C Hamano, Jonathan Tan; +Cc: git, christian.couder



On 7/27/2017 2:55 PM, Junio C Hamano wrote:
> Jonathan Tan <jonathantanmy@google.com> writes:
> 
>> Currently, Git does not support repos with very large numbers of objects
>> or repos that wish to minimize manipulation of certain blobs (for
>> example, because they are very large) very well, even if the user
>> operates mostly on part of the repo, because Git is designed on the
>> assumption that every referenced object is available somewhere in the
>> repo storage.
>>

I very much like the direction this is taking.  Handling missing objects 
gracefully is an important part of the overall partial clone support.

>> Introduce a new repository extension option "extensions.lazyobject", of
>> data type string. If this is set in a repository, Git will tolerate
>> objects being missing in that repository.  When Git needs those objects,
>> it will invoke the command in that option.
> 

I'm very glad you are doing this.  Having never used precious objects I 
was unaware of the extensions concept but it looks like a great way to 
deal with this repo specific option.

> My reading hiccupped after the first sentence, as the problem
> description made it sound like this was a boolean ("are we using
> lazy object feature?"), after reading "data type string".  And then
> "the command in that option" made me hiccup one more time, as it did
> not "click" that "in that option" was trying to say that the string
> is used as the command name (or is it a whole command line?  The
> leading part of the command line to which some arguments are
> appended before it gets invoked as a command? or what?).
> 
> Logically, I think it is more like
> 
>   - extensions.lazyobject can be set to tell Git to consider missing
>     objects in certain cases are not errors;
> 
>   - the value of extensions.lazyobject variable must be a string,
>     which is used to name the command to lazily make the object
>     "appear" in the repository on demand.
> 
>> Teach fsck about the new state of affairs. In this commit, teach fsck
>> that missing objects referenced from the reflog are not an error case;
>> in future commits, fsck will be taught about other cases.
> 
> In any case, sounds like a small and good first step.
> 

I agree completely with the feedback on the description.  That is quite 
the run on sentence. :)

>> +
>> +`lazyObject`
>> +~~~~~~~~~~~~~~~~~
>> +
>> +When the config key `extensions.lazyObject` is set to a string, Git
>> +tolerates objects being missing in the repository. This string contains
>> +the command to be run whenever a missing object is needed.
> 
> This has the same issue but to a lessor degree as there is "string
> contains".  What the command will do (e.g. "makes the object
> magically appear in the object store" or "emits the contents of the
> object to its standard output, so that Git can hash it to make it
> appear in the object store"), and how it is used (e.g. "this is a
> single command name and nothing else", "this is a leading part of
> command line and arguments are appended at the end, before the whole
> thing is passed to the shell to be executed", etc.) will need to be
> clarified in the final version of the series (not necessarily at
> this step---the series can elaborate in the later patches).
> 
>> diff --git a/builtin/fsck.c b/builtin/fsck.c
>> index fb0947009..1cfb8d98c 100644
>> --- a/builtin/fsck.c
>> +++ b/builtin/fsck.c
>> @@ -402,7 +402,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
>>   					xstrfmt("%s@{%"PRItime"}", refname, timestamp));
>>   			obj->flags |= USED;
>>   			mark_object_reachable(obj);
>> -		} else {
>> +		} else if (!repository_format_lazy_object) {
>>   			error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
>>   			errors_found |= ERROR_REACHABLE;
>>   		}
>> diff --git a/cache.h b/cache.h
>> index 6c8242340..9e6bc0a21 100644
>> --- a/cache.h
>> +++ b/cache.h
>> @@ -853,10 +853,12 @@ extern int grafts_replace_parents;
>>   #define GIT_REPO_VERSION 0
>>   #define GIT_REPO_VERSION_READ 1
>>   extern int repository_format_precious_objects;
>> +extern char *repository_format_lazy_object;
> 
> This is not a new problem, but I think these two should be
> called repository_extension_$NAME not repository_format_$NAME.
> 
>> diff --git a/t/t0410-lazy-object.sh b/t/t0410-lazy-object.sh
>> new file mode 100755
>> index 000000000..36442531f
>> --- /dev/null
>> +++ b/t/t0410-lazy-object.sh
>> @@ -0,0 +1,32 @@
>> +#!/bin/sh
>> +
>> +test_description='lazy object'
>> +
>> +. ./test-lib.sh
>> +
>> +delete_object () {
>> +	rm $1/.git/objects/$(echo $2 | cut -c1-2)/$(echo $2 | cut -c3-40)
>> +}
>> +
>> +test_expect_success 'fsck fails on lazy object in reflog' '
>> +	test_create_repo repo &&
>> +	test_commit -C repo 1 &&
>> +
>> +	A=$(git -C repo commit-tree -m a HEAD^{tree}) &&
>> +	B=$(git -C repo commit-tree -m b HEAD^{tree}) &&
>> +
>> +	# Reference $A only from reflog, and delete it
>> +	git -C repo branch mybranch "$A" &&
>> +	git -C repo branch -f mybranch "$B" &&
>> +	delete_object repo "$A" &&
>> +
>> +	test_must_fail git -C repo fsck
>> +'
>> +test_expect_success '...but succeeds if lazyobject is set' '
>> +	git -C repo config core.repositoryformatversion 1 &&
>> +	git -C repo config extensions.lazyobject "arbitrary string" &&
>> +	git -C repo fsck
>> +'
>> +
>> +test_done

^ permalink raw reply	[relevance 4%]

* Re: [PATCH/RFC] contrib: rerere-train overwrites existing resolutions
  @ 2017-07-25 21:18  4% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2017-07-25 21:18 UTC (permalink / raw)
  To: Raman Gupta; +Cc: git

Raman Gupta <rocketraman@gmail.com> writes:

> From 41116889f7eb2ddd590d165d9ca89646f7b15aaf Mon Sep 17 00:00:00 2001
> From: Raman Gupta <rocketraman@gmail.com>
> Date: Tue, 25 Jul 2017 10:28:35 -0400
> Subject: [PATCH] contrib: rerere-train overwrites existing resolutions

These do not belong to the body of the message.

Imagine that your title line appears in "git shortlog --no-merges"
output together with 600 other commits, and you see that list 3
months later.  Can you tell what this change was about?

To me, it sounds like a user is complaining that it overwrites and
loses a precious one, implying that the change is to fix it by being
more careful, i.e. checking if there is an existing one and avoid
overwriting it.

As our convention is to write the log message as if you are giving
an order to the codebase "to behave like so",

	contrib/rerere-train: overwrite existing resolutions

would convey what you are doing better, I would think.

As to the change itself, I do anticipate that a user who is used to
rerere-train will complain that the updated one overwrites existing
resolutions, losing data, as the existing one didn't, and they are
used to the way to correct an incorrect resolution that is recorded
earlier, which is:

 * perform the botched merge again, which will materialize the
   botched merge result in the working tree;

 * do "git rerere forget" for the path;

 * correct the path with the right merge result; and then finally

 * do "git rerere".

If this new behaviour is triggered only when a command line option
is given (e.g. "--overwrite" which is better than "--force"), I
would imagine that it might give us an easier way to achieve the
same thing without learning about "rerere forget".  So I do not
fundamentally oppose to having such an option, but changing the
default behaviour is not going to fly.

> When running rerere-train, the user is explicitly asking the training to
> occur based on the current merge commit. However, if the current cache
> has a resolution for the same conflict (even if out of date or wrong),
> rerere-train does not currently update the rr-cache. Now, forget
> existing resolutions before training so that training is always
> reflective of the trained data.
> ---

Actually, the user is asking to record what is not recorded yet,
which is the originally intended use case.  You may fetch my 'pu'
branch into a repository you already have a copy of git.git, and
want to grab conflict resolutions I did between master..pu that you
still do not know about.  The tool is conservative and avoids
clobbering your resolution if you already have resolved some of the
merges yourself.

In any case, please make it a habit to sign-off your work when
posting here.

>  contrib/rerere-train.sh | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/contrib/rerere-train.sh b/contrib/rerere-train.sh
> index 52ad9e4..a222d38 100755
> --- a/contrib/rerere-train.sh
> +++ b/contrib/rerere-train.sh
> @@ -34,6 +34,7 @@ do
>  		# Cleanly merges
>  		continue
>  	fi
> +	git rerere forget .
>  	if test -s "$GIT_DIR/MERGE_RR"
>  	then
>  		git show -s --pretty=format:"Learning from %h %s" "$commit"

^ permalink raw reply	[relevance 4%]

* [PATCH v3] l10n: de.po: update German translation
  2017-07-14 16:12  2% [PATCH] l10n: de.po: update German translation Ralf Thielow
@ 2017-07-21 17:01  2% ` Ralf Thielow
  0 siblings, 0 replies; 200+ results
From: Ralf Thielow @ 2017-07-21 17:01 UTC (permalink / raw)
  To: git, Matthias Rüster
  Cc: Thomas Rast, Jan Krüger, Christian Stimming, Phillip Szelat,
	Magnus Görlitz, Ralf Thielow

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
v3 contains updated translations in date.c where %lu
turned into %<PRIuMAX>.

 po/de.po | 169 ++++++++++++++++++++++++++++++++-------------------------------
 1 file changed, 87 insertions(+), 82 deletions(-)

diff --git a/po/de.po b/po/de.po
index 347166240..283e68627 100644
--- a/po/de.po
+++ b/po/de.po
@@ -176,26 +176,26 @@ msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
 "git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d"
 
 #: apply.c:979
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d"
 
 #: apply.c:1008
-#, fuzzy, c-format
+#, c-format
 msgid "invalid mode on line %d: %s"
-msgstr "Ungültige Identifikationszeile: %s"
+msgstr "Ungültiger Modus in Zeile %d: %s"
 
 #: apply.c:1326
 #, c-format
 msgid "inconsistent header lines %d and %d"
-msgstr ""
+msgstr "Inkonsistente Kopfzeilen %d und %d."
 
 #: apply.c:1498
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount: unerwartete Zeile: %.*s"
 
 #: apply.c:1567
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
@@ -1525,80 +1525,80 @@ msgstr ""
 #, c-format
 msgid "LF would be replaced by CRLF in %s"
 msgstr "LF würde in %s durch CRLF ersetzt werden."
 
 #: date.c:116
 msgid "in the future"
 msgstr "in der Zukunft"
 
 #: date.c:122
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> second ago"
 msgid_plural "%<PRIuMAX> seconds ago"
-msgstr[0] "vor %lu Sekunde"
-msgstr[1] "vor %lu Sekunden"
+msgstr[0] "vor %<PRIuMAX> Sekunde"
+msgstr[1] "vor %<PRIuMAX> Sekunden"
 
 #: date.c:129
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> minute ago"
 msgid_plural "%<PRIuMAX> minutes ago"
-msgstr[0] "vor %lu Minute"
-msgstr[1] "vor %lu Minuten"
+msgstr[0] "vor %<PRIuMAX> Minute"
+msgstr[1] "vor %<PRIuMAX> Minuten"
 
 #: date.c:136
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> hour ago"
 msgid_plural "%<PRIuMAX> hours ago"
-msgstr[0] "vor %lu Stunde"
-msgstr[1] "vor %lu Stunden"
+msgstr[0] "vor %<PRIuMAX> Stunde"
+msgstr[1] "vor %<PRIuMAX> Stunden"
 
 #: date.c:143
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> day ago"
 msgid_plural "%<PRIuMAX> days ago"
-msgstr[0] "vor %lu Tag"
-msgstr[1] "vor %lu Tagen"
+msgstr[0] "vor %<PRIuMAX> Tag"
+msgstr[1] "vor %<PRIuMAX> Tagen"
 
 #: date.c:149
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> week ago"
 msgid_plural "%<PRIuMAX> weeks ago"
-msgstr[0] "vor %lu Woche"
-msgstr[1] "vor %lu Wochen"
+msgstr[0] "vor %<PRIuMAX> Woche"
+msgstr[1] "vor %<PRIuMAX> Wochen"
 
 #: date.c:156
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> month ago"
 msgid_plural "%<PRIuMAX> months ago"
-msgstr[0] "vor %lu Monat"
-msgstr[1] "vor %lu Monaten"
+msgstr[0] "vor %<PRIuMAX> Monat"
+msgstr[1] "vor %<PRIuMAX> Monaten"
 
 #: date.c:167
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> year"
 msgid_plural "%<PRIuMAX> years"
-msgstr[0] "vor %lu Jahr"
-msgstr[1] "vor %lu Jahren"
+msgstr[0] "vor %<PRIuMAX> Jahr"
+msgstr[1] "vor %<PRIuMAX> Jahren"
 
 #. TRANSLATORS: "%s" is "<n> years"
 #: date.c:170
-#, fuzzy, c-format
+#, c-format
 msgid "%s, %<PRIuMAX> month ago"
 msgid_plural "%s, %<PRIuMAX> months ago"
-msgstr[0] "%s, und %lu Monat"
-msgstr[1] "%s, und %lu Monaten"
+msgstr[0] "%s, und %<PRIuMAX> Monat"
+msgstr[1] "%s, und %<PRIuMAX> Monaten"
 
 #: date.c:175 date.c:180
-#, fuzzy, c-format
+#, c-format
 msgid "%<PRIuMAX> year ago"
 msgid_plural "%<PRIuMAX> years ago"
-msgstr[0] "vor %lu Jahr"
-msgstr[1] "vor %lu Jahren"
+msgstr[0] "vor %<PRIuMAX> Jahr"
+msgstr[1] "vor %<PRIuMAX> Jahren"
 
 #: diffcore-order.c:24
 #, c-format
 msgid "failed to read orderfile '%s'"
 msgstr "Fehler beim Lesen der Reihenfolgedatei '%s'."
 
 #: diffcore-rename.c:536
 msgid "Performing inexact rename detection"
 msgstr "Führe Erkennung für ungenaue Umbenennung aus"
@@ -1940,53 +1940,50 @@ msgid ""
 msgstr ""
 "'%s' scheint ein git-Befehl zu sein, konnte aber\n"
 "nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
 
 #: help.c:336
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Uh oh. Keine Git-Befehle auf Ihrem System vorhanden."
 
 #: help.c:358
-#, fuzzy, c-format
+#, c-format
 msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr ""
-"Warnung: Sie haben den nicht existierenden Git-Befehl '%s' ausgeführt.\n"
-"Setze fort unter der Annahme, dass Sie '%s' gemeint haben."
+msgstr "WARNUNG: Sie haben Git-Befehl '%s' ausgeführt, welcher nicht existiert."
 
 #: help.c:363
 #, c-format
 msgid "Continuing under the assumption that you meant '%s'."
-msgstr ""
+msgstr "Setze fort unter der Annahme, dass Sie '%s' meinten."
 
 #: help.c:368
 #, c-format
 msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
-msgstr ""
+msgstr "Setze in %0.1f Sekunden fort unter der Annahme, dass Sie '%s' meinten."
 
 #: help.c:376
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git: '%s' ist kein Git-Befehl. Siehe 'git --help'."
 
 #: help.c:380
 msgid ""
 "\n"
 "The most similar command is"
 msgid_plural ""
 "\n"
 "The most similar commands are"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "\nDer ähnlichste Befehl ist"
+msgstr[1] "\nDie ähnlichsten Befehle sind"
 
 #: help.c:395
-#, fuzzy
 msgid "git version [<options>]"
-msgstr "git column [<Optionen>]"
+msgstr "git version [<Optionen>]"
 
 #: help.c:456
 #, c-format
 msgid "%s: %s - %s"
 msgstr "%s: %s - %s"
 
 #: help.c:460
 msgid ""
 "\n"
@@ -3411,21 +3408,21 @@ msgstr ""
 "Ausführung erfolgreich: %s\n"
 "Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
 "Führen Sie dann aus:\n"
 "\n"
 "  git rebase --continue\n"
 "\n"
 
 #: sequencer.c:1925
-#, fuzzy, c-format
+#, c-format
 msgid "Applied autostash.\n"
-msgstr "Automatischen Stash angewendet."
+msgstr "Automatischen Stash angewendet.\n"
 
 #: sequencer.c:1937
 #, c-format
 msgid "cannot store %s"
 msgstr "kann %s nicht speichern"
 
 #: sequencer.c:1940 git-rebase.sh:173
 #, c-format
 msgid ""
@@ -3699,21 +3696,21 @@ msgstr "Konnte Eintrag '%s' nicht aus .gitmodules entfernen"
 #: submodule.c:126
 msgid "staging updated .gitmodules failed"
 msgstr "Konnte aktualisierte .gitmodules-Datei nicht zum Commit vormerken"
 
 #: submodule.c:165
 msgid "negative values not allowed for submodule.fetchJobs"
 msgstr "Negative Werte für submodule.fetchJobs nicht erlaubt"
 
 #: submodule.c:376
-#, fuzzy, c-format
+#, c-format
 msgid "in unpopulated submodule '%s'"
-msgstr "Überspringe Submodul '%s'"
+msgstr "In nicht ausgechecktem Submodul '%s'."
 
 #: submodule.c:407
 #, c-format
 msgid "Pathspec '%s' is in submodule '%.*s'"
 msgstr "Pfadspezifikation '%s' befindet sich in Submodul '%.*s'"
 
 #: submodule.c:1337
 #, c-format
 msgid "'%s' not recognized as a git repository"
@@ -4380,23 +4377,23 @@ msgstr "neue Commits, "
 #: wt-status.c:374
 msgid "modified content, "
 msgstr "geänderter Inhalt, "
 
 #: wt-status.c:376
 msgid "untracked content, "
 msgstr "unversionierter Inhalt, "
 
 #: wt-status.c:821
-#, fuzzy, c-format
+#, c-format
 msgid "Your stash currently has %d entry"
 msgid_plural "Your stash currently has %d entries"
-msgstr[0] "Sie sind gerade beim Rebase."
-msgstr[1] "Sie sind gerade beim Rebase."
+msgstr[0] "Ihr Stash hat gerade %d Eintrag"
+msgstr[1] "Ihr Stash hat gerade %d Einträge"
 
 #: wt-status.c:853
 msgid "Submodules changed but not updated:"
 msgstr "Submodule geändert, aber nicht aktualisiert:"
 
 #: wt-status.c:855
 msgid "Submodule changes to be committed:"
 msgstr "Änderungen in Submodul zum Committen:"
 
@@ -4637,21 +4634,20 @@ msgstr "HEAD losgelöst von "
 #: wt-status.c:1586
 msgid "Not currently on any branch."
 msgstr "Im Moment auf keinem Branch."
 
 #: wt-status.c:1606
 msgid "Initial commit"
 msgstr "Initialer Commit"
 
 #: wt-status.c:1607
-#, fuzzy
 msgid "No commits yet"
-msgstr "Keine Commits geparst."
+msgstr "Noch keine Commits"
 
 #: wt-status.c:1621
 msgid "Untracked files"
 msgstr "Unversionierte Dateien"
 
 #: wt-status.c:1623
 msgid "Ignored files"
 msgstr "Ignorierte Dateien"
 
@@ -4724,21 +4720,20 @@ msgstr ""
 "nichts zu committen (benutzen Sie die Option -u, um unversionierte Dateien "
 "anzuzeigen)\n"
 
 #: wt-status.c:1668
 #, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
 
 #: wt-status.c:1780
-#, fuzzy
 msgid "No commits yet on "
-msgstr "Keine Befehle ausgeführt."
+msgstr "Noch keine Commits in "
 
 #: wt-status.c:1784
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Branch)"
 
 #: wt-status.c:1813 wt-status.c:1821
 msgid "behind "
 msgstr "hinterher "
 
@@ -4879,44 +4874,57 @@ msgstr "prüfen ob - auch fehlende - Dateien im Probelauf ignoriert werden"
 #: builtin/add.c:286 builtin/update-index.c:952
 msgid "(+/-)x"
 msgstr "(+/-)x"
 
 #: builtin/add.c:286 builtin/update-index.c:953
 msgid "override the executable bit of the listed files"
 msgstr "das \"ausführbar\"-Bit der aufgelisteten Dateien überschreiben"
 
 #: builtin/add.c:288
-#, fuzzy
 msgid "warn when adding an embedded repository"
-msgstr "ein Bare-Repository erstellen"
+msgstr "warnen wenn eingebettetes Repository hinzugefügt wird"
 
 #: builtin/add.c:303
 #, c-format
 msgid ""
 "You've added another git repository inside your current repository.\n"
 "Clones of the outer repository will not contain the contents of\n"
 "the embedded repository and will not know how to obtain it.\n"
 "If you meant to add a submodule, use:\n"
 "\n"
 "\tgit submodule add <url> %s\n"
 "\n"
 "If you added this path by mistake, you can remove it from the\n"
 "index with:\n"
 "\n"
 "\tgit rm --cached %s\n"
 "\n"
 "See \"git help submodule\" for more information."
 msgstr ""
+"Sie haben ein Git-Repository innerhalb ihres aktuellen Repositories hinzugefügt.\n"
+"Klone des äußeren Repositories werden die Inhalte des eingebetteten Repositories\n"
+"weder enthalten, noch wissen, wie diese zu beschaffen sind.\n"
+"Wenn Sie ein Submodul hinzufügen wollten, benutzen Sie:\n"
+"\n"
+"\tgit submodule add <URL> %s\n"
+"\n"
+"Wenn Sie diesen Pfad aus Versehen hinzugefügt haben, können Sie diesen mit\n"
+"\n"
+"\tgit rm --cached %s\n"
+"\n"
+"vom Index entfernen.\n"
+"\n"
+"Siehe \"git help submodule\" für weitere Informationen."
 
 #: builtin/add.c:331
-#, fuzzy, c-format
+#, c-format
 msgid "adding embedded git repository: %s"
-msgstr "--stdin erfordert ein Git-Repository"
+msgstr "Füge eingebettetes Repository hinzu: %s"
 
 #: builtin/add.c:349
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr "Verwenden Sie -f wenn Sie diese wirklich hinzufügen möchten.\n"
 
 #: builtin/add.c:357
 msgid "adding files failed"
 msgstr "Hinzufügen von Dateien fehlgeschlagen"
@@ -5028,26 +5036,25 @@ msgstr ""
 
 #: builtin/am.c:1173
 #, c-format
 msgid "To restore the original branch and stop patching, run \"%s --abort\"."
 msgstr ""
 "Um den ursprünglichen Branch wiederherzustellen und die Anwendung der "
 "Patches abzubrechen, führen Sie \"%s --abort\" aus."
 
 #: builtin/am.c:1304
-#, fuzzy
 msgid "Patch is empty."
-msgstr "Der aktuelle Patch ist leer."
+msgstr "Patch ist leer."
 
 #: builtin/am.c:1370
-#, fuzzy, c-format
+#, c-format
 msgid "invalid ident line: %.*s"
-msgstr "Ungültige Identifikationszeile: %s"
+msgstr "Ungültige Identifikationszeile: %.*s"
 
 #: builtin/am.c:1392
 #, c-format
 msgid "unable to parse commit %s"
 msgstr "Konnte Commit '%s' nicht parsen."
 
 #: builtin/am.c:1586
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
 msgstr ""
@@ -5148,18 +5155,23 @@ msgstr ""
 "auslassen."
 
 #: builtin/am.c:1922
 msgid ""
 "You still have unmerged paths in your index.\n"
 "You should 'git add' each file with resolved conflicts to mark them as "
 "such.\n"
 "You might run `git rm` on a file to accept \"deleted by them\" for it."
 msgstr ""
+"Sie haben noch immer nicht zusammengeführte Pfade in Ihrem Index.\n"
+"Sie sollten 'git add' für jede Datei mit aufgelösten Konflikten ausführen,\n"
+"um diese als solche zu markieren.\n"
+"Sie können 'git rm' auf Dateien ausführen, um \"von denen gelöscht\" für\n"
+"diese zu akzeptieren."
 
 #: builtin/am.c:2031 builtin/am.c:2035 builtin/am.c:2047 builtin/reset.c:323
 #: builtin/reset.c:331
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "Konnte Objekt '%s' nicht parsen."
 
 #: builtin/am.c:2083
 msgid "failed to clean index"
@@ -6433,19 +6445,19 @@ msgid "Missing branch name; try -b"
 msgstr "Vermisse Branchnamen; versuchen Sie -b"
 
 #: builtin/checkout.c:1261
 msgid "invalid path specification"
 msgstr "ungültige Pfadspezifikation"
 
 #: builtin/checkout.c:1268
 #, c-format
 msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
-msgstr ""
+msgstr "'%s' ist kein Commit und es kann kein Branch '%s' aus diesem erstellt werden."
 
 #: builtin/checkout.c:1272
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr "git checkout: --detach nimmt kein Pfad-Argument '%s'"
 
 #: builtin/checkout.c:1276
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
@@ -6745,19 +6757,19 @@ msgstr ""
 "die Historie eines Klons mit unvollständiger Historie (shallow) mittels\n"
 "Ausschluss eines Commits vertiefen"
 
 #: builtin/clone.c:124
 msgid "clone only one branch, HEAD or --branch"
 msgstr "nur einen Branch klonen, HEAD oder --branch"
 
 #: builtin/clone.c:126
 msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
+msgstr "keine Tags klonen, und auch bei späteren Abrufen nicht beachten"
 
 #: builtin/clone.c:128
 msgid "any cloned submodules will be shallow"
 msgstr "jedes geklonte Submodul mit unvollständiger Historie (shallow)"
 
 #: builtin/clone.c:129 builtin/init-db.c:485
 msgid "gitdir"
 msgstr ".git-Verzeichnis"
 
@@ -6956,20 +6968,20 @@ msgstr ""
 #: builtin/clone.c:1071
 msgid "--shallow-exclude is ignored in local clones; use file:// instead."
 msgstr ""
 "--shallow-exclude wird in lokalen Klonen ignoriert; benutzen Sie stattdessen "
 "file://"
 
 #: builtin/clone.c:1074
 msgid "source repository is shallow, ignoring --local"
 msgstr ""
-"Quelle ist ein Repository mit unvollständiger Historie (shallow),ignoriere --"
-"local"
+"Quelle ist ein Repository mit unvollständiger Historie (shallow),\n"
+"--local wird ignoriert"
 
 #: builtin/clone.c:1079
 msgid "--local is ignored"
 msgstr "--local wird ignoriert"
 
 #: builtin/clone.c:1083
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Weiß nicht wie %s zu klonen ist."
@@ -7374,21 +7386,20 @@ msgstr "Die Option -a kann nicht mit der Angabe von Pfaden verwendet werden."
 #: builtin/commit.c:1342 builtin/commit.c:1617
 msgid "show status concisely"
 msgstr "Status im Kurzformat anzeigen"
 
 #: builtin/commit.c:1344 builtin/commit.c:1619
 msgid "show branch information"
 msgstr "Branchinformationen anzeigen"
 
 #: builtin/commit.c:1346
-#, fuzzy
 msgid "show stash information"
-msgstr "Branchinformationen anzeigen"
+msgstr "Stashinformationen anzeigen"
 
 #: builtin/commit.c:1348
 msgid "version"
 msgstr "Version"
 
 #: builtin/commit.c:1348 builtin/commit.c:1621 builtin/push.c:530
 #: builtin/worktree.c:449
 msgid "machine-readable output"
 msgstr "maschinenlesbare Ausgabe"
@@ -7783,22 +7794,20 @@ msgid ""
 "#\temail = %s\n"
 msgstr ""
 "# Das ist Git's benutzerspezifische Konfiguraionsdatei.\n"
 "[user]\n"
 "# Bitte passen Sie die folgenden Zeilen an und kommentieren Sie diese aus:\n"
 "#\tname = %s\n"
 "#\temail = %s\n"
 
 #: builtin/config.c:499
-#, fuzzy
 msgid "--local can only be used inside a git repository"
-msgstr ""
-"Die Option --cached kann nicht außerhalb eines Repositories verwendet werden."
+msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
 
 #: builtin/config.c:621
 #, c-format
 msgid "cannot create configuration file %s"
 msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
 
 #: builtin/config.c:633
 #, c-format
 msgid ""
@@ -8263,18 +8272,20 @@ msgstr "Verzeichnis"
 #: builtin/fetch.c:127
 msgid "prepend this to submodule path output"
 msgstr "dies an die Ausgabe der Submodul-Pfade voranstellen"
 
 #: builtin/fetch.c:130
 msgid ""
 "default for recursive fetching of submodules (lower priority than config "
 "files)"
 msgstr ""
+"Standard für die rekursive Anforderung von Submodulen (geringere Priorität\n"
+"als Konfigurationsdateien)"
 
 #: builtin/fetch.c:134 builtin/pull.c:212
 msgid "accept refs that update .git/shallow"
 msgstr "Referenzen, die .git/shallow aktualisieren, akzeptieren"
 
 #: builtin/fetch.c:135 builtin/pull.c:214
 msgid "refmap"
 msgstr "Refmap"
 
@@ -8933,21 +8944,20 @@ msgstr "--no-index oder --untracked können nicht mit Commits verwendet werden"
 msgid "unable to resolve revision: %s"
 msgstr "Konnte Commit nicht auflösen: %s"
 
 #: builtin/grep.c:1245 builtin/index-pack.c:1490
 #, c-format
 msgid "invalid number of threads specified (%d)"
 msgstr "ungültige Anzahl von Threads angegeben (%d)"
 
 #: builtin/grep.c:1250
-#, fuzzy
 msgid "no threads support, ignoring --threads"
-msgstr "keine Unterstützung von Threads, '%s' wird ignoriert"
+msgstr "keine Unterstützung von Threads, --threads wird ignoriert"
 
 #: builtin/grep.c:1281
 msgid "--open-files-in-pager only works on the worktree"
 msgstr ""
 "Die Option --open-files-in-pager kann nur innerhalb des "
 "Arbeitsverzeichnisses verwendet werden."
 
 #: builtin/grep.c:1304
 msgid "option not supported with --recurse-submodules."
@@ -10104,19 +10114,19 @@ msgstr "vollständige Pfadnamen verwenden"
 #: builtin/ls-tree.c:144
 msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
 "das gesamte Verzeichnis auflisten; nicht nur das aktuelle Verzeichnis "
 "(impliziert --full-name)"
 
 #: builtin/mailsplit.c:241
 #, c-format
 msgid "empty mbox: '%s'"
-msgstr ""
+msgstr "Leere mbox: '%s'"
 
 #: builtin/merge.c:47
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<Optionen>] [<Commit>...]"
 
 #: builtin/merge.c:48
 msgid "git merge --abort"
 msgstr "git merge --abort"
 
@@ -11426,19 +11436,18 @@ msgstr "kann \"prune\" in precious-objects Repository nicht ausführen"
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Ungültiger Wert für %s: %s"
 
 #: builtin/pull.c:76
 msgid "git pull [<options>] [<repository> [<refspec>...]]"
 msgstr "git pull [<Optionen>] [<Repository> [<Refspec>...]]"
 
 #: builtin/pull.c:124
-#, fuzzy
 msgid "control for recursive fetching of submodules"
 msgstr "rekursive Anforderungen von Submodulen kontrollieren"
 
 #: builtin/pull.c:128
 msgid "Options related to merging"
 msgstr "Optionen bezogen auf Merge"
 
 #: builtin/pull.c:131
 msgid "incorporate changes by rebasing rather than merging"
@@ -11603,19 +11612,19 @@ msgstr ""
 msgid "Cannot merge multiple branches into empty head."
 msgstr "Kann nicht mehrere Branches in einen leeren Branch zusammenführen."
 
 #: builtin/pull.c:901
 msgid "Cannot rebase onto multiple branches."
 msgstr "Kann Rebase nicht auf mehrere Branches ausführen."
 
 #: builtin/pull.c:908
 msgid "cannot rebase with locally recorded submodule modifications"
-msgstr ""
+msgstr "Kann Rebase nicht mit lokal aufgezeichneten Änderungen in Submodulen ausführen."
 
 #: builtin/push.c:17
 msgid "git push [<options>] [<repository> [<refspec>...]]"
 msgstr "git push [<Optionen>] [<Repository> [<Refspec>...]]"
 
 #: builtin/push.c:90
 msgid "tag shorthand without <tag>"
 msgstr "Kurzschrift für Tag ohne <Tag>"
 
@@ -12670,21 +12679,20 @@ msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
 "gleiches wie oben, aber die Speichergröße anstatt der\n"
 "Anzahl der Einträge limitieren"
 
 #: builtin/repack.c:194
 msgid "limits the maximum delta depth"
 msgstr "die maximale Delta-Tiefe limitieren"
 
 #: builtin/repack.c:196
-#, fuzzy
 msgid "limits the maximum number of threads"
-msgstr "die maximale Delta-Tiefe limitieren"
+msgstr "maximale Anzahl von Threads limitieren"
 
 #: builtin/repack.c:198
 msgid "maximum size of each packfile"
 msgstr "maximale Größe für jede Paketdatei"
 
 #: builtin/repack.c:200
 msgid "repack objects in packs marked with .keep"
 msgstr ""
 "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
@@ -14996,21 +15004,20 @@ msgstr "Speicherte Arbeitsverzeichnis und Index-Status $stash_msg"
 msgid "Cannot remove worktree changes"
 msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
 
 #: git-stash.sh:474
 #, sh-format
 msgid "unknown option: $opt"
 msgstr "unbekannte Option: $opt"
 
 #: git-stash.sh:487
-#, fuzzy
 msgid "No stash entries found."
-msgstr "Kein Stash-Eintrag gefunden."
+msgstr "Keine Stash-Einträge gefunden."
 
 #: git-stash.sh:494
 #, sh-format
 msgid "Too many revisions specified: $REV"
 msgstr "Zu viele Commits angegeben: $REV"
 
 #: git-stash.sh:509
 #, sh-format
 msgid "$reference is not a valid reference"
@@ -15037,34 +15044,32 @@ msgstr "Kann \"stash\" nicht anwenden, solang ein Merge im Gange ist"
 #: git-stash.sh:568
 msgid "Conflicts in index. Try without --index."
 msgstr "Konflikte im Index. Versuchen Sie es ohne --index."
 
 #: git-stash.sh:570
 msgid "Could not save index tree"
 msgstr "Konnte Index-Verzeichnis nicht speichern"
 
 #: git-stash.sh:579
-#, fuzzy
 msgid "Could not restore untracked files from stash entry"
-msgstr "Konnte unversionierte Dateien vom Stash nicht wiederherstellen"
+msgstr "Konnte unversionierte Dateien vom Stash-Eintrag nicht wiederherstellen."
 
 #: git-stash.sh:604
 msgid "Cannot unstage modified files"
 msgstr "Kann geänderte Dateien nicht aus dem Index entfernen"
 
 #: git-stash.sh:619
 msgid "Index was not unstashed."
 msgstr "Index wurde nicht aus dem Stash zurückgeladen."
 
 #: git-stash.sh:633
-#, fuzzy
 msgid "The stash entry is kept in case you need it again."
-msgstr "Der Stash wird behalten, im Falle Sie benötigen diesen nochmal."
+msgstr "Der Stash-Eintrag wird behalten, im Falle Sie benötigen diesen nochmal."
 
 #: git-stash.sh:642
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Gelöscht ${REV} ($s)"
 
 #: git-stash.sh:643
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
@@ -16643,19 +16648,19 @@ msgstr "Der erforderliche SMTP-Server ist nicht korrekt definiert."
 
 #: git-send-email.perl:1411
 #, perl-format
 msgid "Server does not support STARTTLS! %s"
 msgstr "Server unterstützt kein STARTTLS! %s"
 
 #: git-send-email.perl:1416 git-send-email.perl:1420
 #, perl-format
 msgid "STARTTLS failed! %s"
-msgstr ""
+msgstr "STARTTLS fehlgeschlagen! %s"
 
 #: git-send-email.perl:1430
 msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
 msgstr ""
 "Konnte SMTP nicht korrekt initialisieren. Bitte prüfen Sie Ihre "
 "Konfiguration\n"
 "und benutzen Sie --smtp-debug."
 
 #: git-send-email.perl:1448
-- 
2.14.0.rc0.284.gd933b75aa


^ permalink raw reply related	[relevance 2%]

* [PATCH v2] l10n: de.po: update German translation
  @ 2017-07-21 15:11  2% ` Ralf Thielow
  0 siblings, 0 replies; 200+ results
From: Ralf Thielow @ 2017-07-21 15:11 UTC (permalink / raw)
  To: git, Matthias Rüster
  Cc: Thomas Rast, Jan Krüger, Christian Stimming, Phillip Szelat,
	Magnus Görlitz, Ralf Thielow

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
Hi Matthias,

2017-07-20 20:36 GMT+02:00 Matthias Rüster <matthias.ruester@gmail.com>:
> Hi Ralf,
>
> I think the following should be "hinzugefügt":
>

Sure. Thanks for review!

Ciao,
Ralf

 po/de.po | 123 +++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 64 insertions(+), 59 deletions(-)

diff --git a/po/de.po b/po/de.po
index 5619fa962..f905c7ec7 100644
--- a/po/de.po
+++ b/po/de.po
@@ -176,26 +176,26 @@ msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
 "git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d"
 
 #: apply.c:979
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d"
 
 #: apply.c:1008
-#, fuzzy, c-format
+#, c-format
 msgid "invalid mode on line %d: %s"
-msgstr "Ungültige Identifikationszeile: %s"
+msgstr "Ungültiger Modus in Zeile %d: %s"
 
 #: apply.c:1326
 #, c-format
 msgid "inconsistent header lines %d and %d"
-msgstr ""
+msgstr "Inkonsistente Kopfzeilen %d und %d."
 
 #: apply.c:1498
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount: unerwartete Zeile: %.*s"
 
 #: apply.c:1567
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
@@ -1528,27 +1528,27 @@ msgstr "LF würde in %s durch CRLF ersetzt werden."
 
 #: date.c:116
 msgid "in the future"
 msgstr "in der Zukunft"
 
 #: date.c:122 date.c:129 date.c:136 date.c:143 date.c:149 date.c:156 date.c:167
 #: date.c:175 date.c:180
 msgid "%"
 msgid_plural "%"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%"
+msgstr[1] "%"
 
 #. TRANSLATORS: "%s" is "<n> years"
 #: date.c:170
 msgid "%s, %"
 msgid_plural "%s, %"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%s, %"
+msgstr[1] "%s, %"
 
 #: diffcore-order.c:24
 #, c-format
 msgid "failed to read orderfile '%s'"
 msgstr "Fehler beim Lesen der Reihenfolgedatei '%s'."
 
 #: diffcore-rename.c:536
 msgid "Performing inexact rename detection"
 msgstr "Führe Erkennung für ungenaue Umbenennung aus"
@@ -1890,53 +1890,50 @@ msgid ""
 msgstr ""
 "'%s' scheint ein git-Befehl zu sein, konnte aber\n"
 "nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
 
 #: help.c:336
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Uh oh. Keine Git-Befehle auf Ihrem System vorhanden."
 
 #: help.c:358
-#, fuzzy, c-format
+#, c-format
 msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr ""
-"Warnung: Sie haben den nicht existierenden Git-Befehl '%s' ausgeführt.\n"
-"Setze fort unter der Annahme, dass Sie '%s' gemeint haben."
+msgstr "WARNUNG: Sie haben Git-Befehl '%s' ausgeführt, welcher nicht existiert."
 
 #: help.c:363
 #, c-format
 msgid "Continuing under the assumption that you meant '%s'."
-msgstr ""
+msgstr "Setze fort unter der Annahme, dass Sie '%s' meinten."
 
 #: help.c:368
 #, c-format
 msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
-msgstr ""
+msgstr "Setze in %0.1f Sekunden fort unter der Annahme, dass Sie '%s' meinten."
 
 #: help.c:376
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git: '%s' ist kein Git-Befehl. Siehe 'git --help'."
 
 #: help.c:380
 msgid ""
 "\n"
 "The most similar command is"
 msgid_plural ""
 "\n"
 "The most similar commands are"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "\nDer ähnlichste Befehl ist"
+msgstr[1] "\nDie ähnlichsten Befehle sind"
 
 #: help.c:395
-#, fuzzy
 msgid "git version [<options>]"
-msgstr "git column [<Optionen>]"
+msgstr "git version [<Optionen>]"
 
 #: help.c:456
 #, c-format
 msgid "%s: %s - %s"
 msgstr "%s: %s - %s"
 
 #: help.c:460
 msgid ""
 "\n"
@@ -3361,21 +3358,21 @@ msgstr ""
 "Ausführung erfolgreich: %s\n"
 "Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
 "Führen Sie dann aus:\n"
 "\n"
 "  git rebase --continue\n"
 "\n"
 
 #: sequencer.c:1925
-#, fuzzy, c-format
+#, c-format
 msgid "Applied autostash.\n"
-msgstr "Automatischen Stash angewendet."
+msgstr "Automatischen Stash angewendet.\n"
 
 #: sequencer.c:1937
 #, c-format
 msgid "cannot store %s"
 msgstr "kann %s nicht speichern"
 
 #: sequencer.c:1940 git-rebase.sh:173
 #, c-format
 msgid ""
@@ -3649,21 +3646,21 @@ msgstr "Konnte Eintrag '%s' nicht aus .gitmodules entfernen"
 #: submodule.c:126
 msgid "staging updated .gitmodules failed"
 msgstr "Konnte aktualisierte .gitmodules-Datei nicht zum Commit vormerken"
 
 #: submodule.c:165
 msgid "negative values not allowed for submodule.fetchJobs"
 msgstr "Negative Werte für submodule.fetchJobs nicht erlaubt"
 
 #: submodule.c:376
-#, fuzzy, c-format
+#, c-format
 msgid "in unpopulated submodule '%s'"
-msgstr "Überspringe Submodul '%s'"
+msgstr "In nicht ausgechecktem Submodul '%s'."
 
 #: submodule.c:407
 #, c-format
 msgid "Pathspec '%s' is in submodule '%.*s'"
 msgstr "Pfadspezifikation '%s' befindet sich in Submodul '%.*s'"
 
 #: submodule.c:1337
 #, c-format
 msgid "'%s' not recognized as a git repository"
@@ -4330,23 +4327,23 @@ msgstr "neue Commits, "
 #: wt-status.c:374
 msgid "modified content, "
 msgstr "geänderter Inhalt, "
 
 #: wt-status.c:376
 msgid "untracked content, "
 msgstr "unversionierter Inhalt, "
 
 #: wt-status.c:821
-#, fuzzy, c-format
+#, c-format
 msgid "Your stash currently has %d entry"
 msgid_plural "Your stash currently has %d entries"
-msgstr[0] "Sie sind gerade beim Rebase."
-msgstr[1] "Sie sind gerade beim Rebase."
+msgstr[0] "Ihr Stash hat gerade %d Eintrag"
+msgstr[1] "Ihr Stash hat gerade %d Einträge"
 
 #: wt-status.c:853
 msgid "Submodules changed but not updated:"
 msgstr "Submodule geändert, aber nicht aktualisiert:"
 
 #: wt-status.c:855
 msgid "Submodule changes to be committed:"
 msgstr "Änderungen in Submodul zum Committen:"
 
@@ -4587,21 +4584,20 @@ msgstr "HEAD losgelöst von "
 #: wt-status.c:1586
 msgid "Not currently on any branch."
 msgstr "Im Moment auf keinem Branch."
 
 #: wt-status.c:1606
 msgid "Initial commit"
 msgstr "Initialer Commit"
 
 #: wt-status.c:1607
-#, fuzzy
 msgid "No commits yet"
-msgstr "Keine Commits geparst."
+msgstr "Noch keine Commits"
 
 #: wt-status.c:1621
 msgid "Untracked files"
 msgstr "Unversionierte Dateien"
 
 #: wt-status.c:1623
 msgid "Ignored files"
 msgstr "Ignorierte Dateien"
 
@@ -4674,21 +4670,20 @@ msgstr ""
 "nichts zu committen (benutzen Sie die Option -u, um unversionierte Dateien "
 "anzuzeigen)\n"
 
 #: wt-status.c:1668
 #, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
 
 #: wt-status.c:1780
-#, fuzzy
 msgid "No commits yet on "
-msgstr "Keine Befehle ausgeführt."
+msgstr "Noch keine Commits in "
 
 #: wt-status.c:1784
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Branch)"
 
 #: wt-status.c:1813 wt-status.c:1821
 msgid "behind "
 msgstr "hinterher "
 
@@ -4834,44 +4829,57 @@ msgstr "prüfen ob - auch fehlende - Dateien im Probelauf ignoriert werden"
 #: builtin/add.c:286 builtin/update-index.c:952
 msgid "(+/-)x"
 msgstr "(+/-)x"
 
 #: builtin/add.c:286 builtin/update-index.c:953
 msgid "override the executable bit of the listed files"
 msgstr "das \"ausführbar\"-Bit der aufgelisteten Dateien überschreiben"
 
 #: builtin/add.c:288
-#, fuzzy
 msgid "warn when adding an embedded repository"
-msgstr "ein Bare-Repository erstellen"
+msgstr "warnen wenn eingebettetes Repository hinzugefügt wird"
 
 #: builtin/add.c:303
 #, c-format
 msgid ""
 "You've added another git repository inside your current repository.\n"
 "Clones of the outer repository will not contain the contents of\n"
 "the embedded repository and will not know how to obtain it.\n"
 "If you meant to add a submodule, use:\n"
 "\n"
 "\tgit submodule add <url> %s\n"
 "\n"
 "If you added this path by mistake, you can remove it from the\n"
 "index with:\n"
 "\n"
 "\tgit rm --cached %s\n"
 "\n"
 "See \"git help submodule\" for more information."
 msgstr ""
+"Sie haben ein Git-Repository innerhalb ihres aktuellen Repositories hinzugefügt.\n"
+"Klone des äußeren Repositories werden die Inhalte des eingebetteten Repositories\n"
+"weder enthalten, noch wissen, wie diese zu beschaffen sind.\n"
+"Wenn Sie ein Submodul hinzufügen wollten, benutzen Sie:\n"
+"\n"
+"\tgit submodule add <URL> %s\n"
+"\n"
+"Wenn Sie diesen Pfad aus Versehen hinzugefügt haben, können Sie diesen mit\n"
+"\n"
+"\tgit rm --cached %s\n"
+"\n"
+"vom Index entfernen.\n"
+"\n"
+"Siehe \"git help submodule\" für weitere Informationen."
 
 #: builtin/add.c:331
-#, fuzzy, c-format
+#, c-format
 msgid "adding embedded git repository: %s"
-msgstr "--stdin erfordert ein Git-Repository"
+msgstr "Füge eingebettetes Repository hinzu: %s"
 
 #: builtin/add.c:349
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr "Verwenden Sie -f wenn Sie diese wirklich hinzufügen möchten.\n"
 
 #: builtin/add.c:357
 msgid "adding files failed"
 msgstr "Hinzufügen von Dateien fehlgeschlagen"
@@ -4983,26 +4991,25 @@ msgstr ""
 
 #: builtin/am.c:1173
 #, c-format
 msgid "To restore the original branch and stop patching, run \"%s --abort\"."
 msgstr ""
 "Um den ursprünglichen Branch wiederherzustellen und die Anwendung der "
 "Patches abzubrechen, führen Sie \"%s --abort\" aus."
 
 #: builtin/am.c:1304
-#, fuzzy
 msgid "Patch is empty."
-msgstr "Der aktuelle Patch ist leer."
+msgstr "Patch ist leer."
 
 #: builtin/am.c:1370
-#, fuzzy, c-format
+#, c-format
 msgid "invalid ident line: %.*s"
-msgstr "Ungültige Identifikationszeile: %s"
+msgstr "Ungültige Identifikationszeile: %.*s"
 
 #: builtin/am.c:1392
 #, c-format
 msgid "unable to parse commit %s"
 msgstr "Konnte Commit '%s' nicht parsen."
 
 #: builtin/am.c:1586
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
 msgstr ""
@@ -5103,18 +5110,23 @@ msgstr ""
 "auslassen."
 
 #: builtin/am.c:1922
 msgid ""
 "You still have unmerged paths in your index.\n"
 "You should 'git add' each file with resolved conflicts to mark them as "
 "such.\n"
 "You might run `git rm` on a file to accept \"deleted by them\" for it."
 msgstr ""
+"Sie haben noch immer nicht zusammengeführte Pfade in Ihrem Index.\n"
+"Sie sollten 'git add' für jede Datei mit aufgelösten Konflikten ausführen,\n"
+"um diese als solche zu markieren.\n"
+"Sie können 'git rm' auf Dateien ausführen, um \"von denen gelöscht\" für\n"
+"diese zu akzeptieren."
 
 #: builtin/am.c:2031 builtin/am.c:2035 builtin/am.c:2047 builtin/reset.c:323
 #: builtin/reset.c:331
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "Konnte Objekt '%s' nicht parsen."
 
 #: builtin/am.c:2083
 msgid "failed to clean index"
@@ -6388,19 +6400,19 @@ msgid "Missing branch name; try -b"
 msgstr "Vermisse Branchnamen; versuchen Sie -b"
 
 #: builtin/checkout.c:1261
 msgid "invalid path specification"
 msgstr "ungültige Pfadspezifikation"
 
 #: builtin/checkout.c:1268
 #, c-format
 msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
-msgstr ""
+msgstr "'%s' ist kein Commit und es kann kein Branch '%s' aus diesem erstellt werden."
 
 #: builtin/checkout.c:1272
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr "git checkout: --detach nimmt kein Pfad-Argument '%s'"
 
 #: builtin/checkout.c:1276
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
@@ -6700,19 +6712,19 @@ msgstr ""
 "die Historie eines Klons mit unvollständiger Historie (shallow) mittels\n"
 "Ausschluss eines Commits vertiefen"
 
 #: builtin/clone.c:124
 msgid "clone only one branch, HEAD or --branch"
 msgstr "nur einen Branch klonen, HEAD oder --branch"
 
 #: builtin/clone.c:126
 msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
+msgstr "keine Tags klonen, und auch bei späteren Abrufen nicht beachten"
 
 #: builtin/clone.c:128
 msgid "any cloned submodules will be shallow"
 msgstr "jedes geklonte Submodul mit unvollständiger Historie (shallow)"
 
 #: builtin/clone.c:129 builtin/init-db.c:485
 msgid "gitdir"
 msgstr ".git-Verzeichnis"
 
@@ -6906,20 +6918,20 @@ msgstr ""
 #: builtin/clone.c:1071
 msgid "--shallow-exclude is ignored in local clones; use file:// instead."
 msgstr ""
 "--shallow-exclude wird in lokalen Klonen ignoriert; benutzen Sie stattdessen "
 "file://"
 
 #: builtin/clone.c:1074
 msgid "source repository is shallow, ignoring --local"
 msgstr ""
-"Quelle ist ein Repository mit unvollständiger Historie (shallow),ignoriere --"
-"local"
+"Quelle ist ein Repository mit unvollständiger Historie (shallow),\n"
+"--local wird ignoriert"
 
 #: builtin/clone.c:1079
 msgid "--local is ignored"
 msgstr "--local wird ignoriert"
 
 #: builtin/clone.c:1083
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Weiß nicht wie %s zu klonen ist."
@@ -7324,21 +7336,20 @@ msgstr "Die Option -a kann nicht mit der Angabe von Pfaden verwendet werden."
 #: builtin/commit.c:1342 builtin/commit.c:1617
 msgid "show status concisely"
 msgstr "Status im Kurzformat anzeigen"
 
 #: builtin/commit.c:1344 builtin/commit.c:1619
 msgid "show branch information"
 msgstr "Branchinformationen anzeigen"
 
 #: builtin/commit.c:1346
-#, fuzzy
 msgid "show stash information"
-msgstr "Branchinformationen anzeigen"
+msgstr "Stashinformationen anzeigen"
 
 #: builtin/commit.c:1348
 msgid "version"
 msgstr "Version"
 
 #: builtin/commit.c:1348 builtin/commit.c:1621 builtin/push.c:530
 #: builtin/worktree.c:449
 msgid "machine-readable output"
 msgstr "maschinenlesbare Ausgabe"
@@ -7733,22 +7744,20 @@ msgid ""
 "#\temail = %s\n"
 msgstr ""
 "# Das ist Git's benutzerspezifische Konfiguraionsdatei.\n"
 "[user]\n"
 "# Bitte passen Sie die folgenden Zeilen an und kommentieren Sie diese aus:\n"
 "#\tname = %s\n"
 "#\temail = %s\n"
 
 #: builtin/config.c:499
-#, fuzzy
 msgid "--local can only be used inside a git repository"
-msgstr ""
-"Die Option --cached kann nicht außerhalb eines Repositories verwendet werden."
+msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
 
 #: builtin/config.c:621
 #, c-format
 msgid "cannot create configuration file %s"
 msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
 
 #: builtin/config.c:633
 #, c-format
 msgid ""
@@ -8213,18 +8222,20 @@ msgstr "Verzeichnis"
 #: builtin/fetch.c:127
 msgid "prepend this to submodule path output"
 msgstr "dies an die Ausgabe der Submodul-Pfade voranstellen"
 
 #: builtin/fetch.c:130
 msgid ""
 "default for recursive fetching of submodules (lower priority than config "
 "files)"
 msgstr ""
+"Standard für die rekursive Anforderung von Submodulen (geringere Priorität\n"
+"als Konfigurationsdateien)"
 
 #: builtin/fetch.c:134 builtin/pull.c:212
 msgid "accept refs that update .git/shallow"
 msgstr "Referenzen, die .git/shallow aktualisieren, akzeptieren"
 
 #: builtin/fetch.c:135 builtin/pull.c:214
 msgid "refmap"
 msgstr "Refmap"
 
@@ -8883,21 +8894,20 @@ msgstr "--no-index oder --untracked können nicht mit Commits verwendet werden"
 msgid "unable to resolve revision: %s"
 msgstr "Konnte Commit nicht auflösen: %s"
 
 #: builtin/grep.c:1245 builtin/index-pack.c:1490
 #, c-format
 msgid "invalid number of threads specified (%d)"
 msgstr "ungültige Anzahl von Threads angegeben (%d)"
 
 #: builtin/grep.c:1250
-#, fuzzy
 msgid "no threads support, ignoring --threads"
-msgstr "keine Unterstützung von Threads, '%s' wird ignoriert"
+msgstr "keine Unterstützung von Threads, --threads wird ignoriert"
 
 #: builtin/grep.c:1281
 msgid "--open-files-in-pager only works on the worktree"
 msgstr ""
 "Die Option --open-files-in-pager kann nur innerhalb des "
 "Arbeitsverzeichnisses verwendet werden."
 
 #: builtin/grep.c:1304
 msgid "option not supported with --recurse-submodules."
@@ -10054,19 +10064,19 @@ msgstr "vollständige Pfadnamen verwenden"
 #: builtin/ls-tree.c:144
 msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
 "das gesamte Verzeichnis auflisten; nicht nur das aktuelle Verzeichnis "
 "(impliziert --full-name)"
 
 #: builtin/mailsplit.c:241
 #, c-format
 msgid "empty mbox: '%s'"
-msgstr ""
+msgstr "Leere mbox: '%s'"
 
 #: builtin/merge.c:47
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<Optionen>] [<Commit>...]"
 
 #: builtin/merge.c:48
 msgid "git merge --abort"
 msgstr "git merge --abort"
 
@@ -11376,19 +11386,18 @@ msgstr "kann \"prune\" in precious-objects Repository nicht ausführen"
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Ungültiger Wert für %s: %s"
 
 #: builtin/pull.c:76
 msgid "git pull [<options>] [<repository> [<refspec>...]]"
 msgstr "git pull [<Optionen>] [<Repository> [<Refspec>...]]"
 
 #: builtin/pull.c:124
-#, fuzzy
 msgid "control for recursive fetching of submodules"
 msgstr "rekursive Anforderungen von Submodulen kontrollieren"
 
 #: builtin/pull.c:128
 msgid "Options related to merging"
 msgstr "Optionen bezogen auf Merge"
 
 #: builtin/pull.c:131
 msgid "incorporate changes by rebasing rather than merging"
@@ -11553,19 +11562,19 @@ msgstr ""
 msgid "Cannot merge multiple branches into empty head."
 msgstr "Kann nicht mehrere Branches in einen leeren Branch zusammenführen."
 
 #: builtin/pull.c:901
 msgid "Cannot rebase onto multiple branches."
 msgstr "Kann Rebase nicht auf mehrere Branches ausführen."
 
 #: builtin/pull.c:908
 msgid "cannot rebase with locally recorded submodule modifications"
-msgstr ""
+msgstr "Kann Rebase nicht mit lokal aufgezeichneten Änderungen in Submodulen ausführen."
 
 #: builtin/push.c:17
 msgid "git push [<options>] [<repository> [<refspec>...]]"
 msgstr "git push [<Optionen>] [<Repository> [<Refspec>...]]"
 
 #: builtin/push.c:90
 msgid "tag shorthand without <tag>"
 msgstr "Kurzschrift für Tag ohne <Tag>"
 
@@ -12620,21 +12629,20 @@ msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
 "gleiches wie oben, aber die Speichergröße anstatt der\n"
 "Anzahl der Einträge limitieren"
 
 #: builtin/repack.c:194
 msgid "limits the maximum delta depth"
 msgstr "die maximale Delta-Tiefe limitieren"
 
 #: builtin/repack.c:196
-#, fuzzy
 msgid "limits the maximum number of threads"
-msgstr "die maximale Delta-Tiefe limitieren"
+msgstr "maximale Anzahl von Threads limitieren"
 
 #: builtin/repack.c:198
 msgid "maximum size of each packfile"
 msgstr "maximale Größe für jede Paketdatei"
 
 #: builtin/repack.c:200
 msgid "repack objects in packs marked with .keep"
 msgstr ""
 "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
@@ -14946,21 +14954,20 @@ msgstr "Speicherte Arbeitsverzeichnis und Index-Status $stash_msg"
 msgid "Cannot remove worktree changes"
 msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
 
 #: git-stash.sh:474
 #, sh-format
 msgid "unknown option: $opt"
 msgstr "unbekannte Option: $opt"
 
 #: git-stash.sh:487
-#, fuzzy
 msgid "No stash entries found."
-msgstr "Kein Stash-Eintrag gefunden."
+msgstr "Keine Stash-Einträge gefunden."
 
 #: git-stash.sh:494
 #, sh-format
 msgid "Too many revisions specified: $REV"
 msgstr "Zu viele Commits angegeben: $REV"
 
 #: git-stash.sh:509
 #, sh-format
 msgid "$reference is not a valid reference"
@@ -14987,34 +14994,32 @@ msgstr "Kann \"stash\" nicht anwenden, solang ein Merge im Gange ist"
 #: git-stash.sh:568
 msgid "Conflicts in index. Try without --index."
 msgstr "Konflikte im Index. Versuchen Sie es ohne --index."
 
 #: git-stash.sh:570
 msgid "Could not save index tree"
 msgstr "Konnte Index-Verzeichnis nicht speichern"
 
 #: git-stash.sh:579
-#, fuzzy
 msgid "Could not restore untracked files from stash entry"
-msgstr "Konnte unversionierte Dateien vom Stash nicht wiederherstellen"
+msgstr "Konnte unversionierte Dateien vom Stash-Eintrag nicht wiederherstellen."
 
 #: git-stash.sh:604
 msgid "Cannot unstage modified files"
 msgstr "Kann geänderte Dateien nicht aus dem Index entfernen"
 
 #: git-stash.sh:619
 msgid "Index was not unstashed."
 msgstr "Index wurde nicht aus dem Stash zurückgeladen."
 
 #: git-stash.sh:633
-#, fuzzy
 msgid "The stash entry is kept in case you need it again."
-msgstr "Der Stash wird behalten, im Falle Sie benötigen diesen nochmal."
+msgstr "Der Stash-Eintrag wird behalten, im Falle Sie benötigen diesen nochmal."
 
 #: git-stash.sh:642
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Gelöscht ${REV} ($s)"
 
 #: git-stash.sh:643
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
@@ -16593,19 +16598,19 @@ msgstr "Der erforderliche SMTP-Server ist nicht korrekt definiert."
 
 #: git-send-email.perl:1411
 #, perl-format
 msgid "Server does not support STARTTLS! %s"
 msgstr "Server unterstützt kein STARTTLS! %s"
 
 #: git-send-email.perl:1416 git-send-email.perl:1420
 #, perl-format
 msgid "STARTTLS failed! %s"
-msgstr ""
+msgstr "STARTTLS fehlgeschlagen! %s"
 
 #: git-send-email.perl:1430
 msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
 msgstr ""
 "Konnte SMTP nicht korrekt initialisieren. Bitte prüfen Sie Ihre "
 "Konfiguration\n"
 "und benutzen Sie --smtp-debug."
 
 #: git-send-email.perl:1448
-- 
2.14.0.rc0.284.gd933b75aa


^ permalink raw reply related	[relevance 2%]

* [PATCH] l10n: de.po: update German translation
@ 2017-07-14 16:12  2% Ralf Thielow
  2017-07-21 17:01  2% ` [PATCH v3] " Ralf Thielow
  0 siblings, 1 reply; 200+ results
From: Ralf Thielow @ 2017-07-14 16:12 UTC (permalink / raw)
  To: git
  Cc: Thomas Rast, Jan Krüger, Christian Stimming, Phillip Szelat,
	Matthias Rüster, Magnus Görlitz, Ralf Thielow

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 po/de.po | 123 +++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 64 insertions(+), 59 deletions(-)

diff --git a/po/de.po b/po/de.po
index b9e076f93..f4cb9bf2d 100644
--- a/po/de.po
+++ b/po/de.po
@@ -176,26 +176,26 @@ msgid "git apply: bad git-diff - inconsistent old filename on line %d"
 msgstr ""
 "git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d"
 
 #: apply.c:979
 #, c-format
 msgid "git apply: bad git-diff - expected /dev/null on line %d"
 msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d"
 
 #: apply.c:1008
-#, fuzzy, c-format
+#, c-format
 msgid "invalid mode on line %d: %s"
-msgstr "Ungültige Identifikationszeile: %s"
+msgstr "Ungültiger Modus in Zeile %d: %s"
 
 #: apply.c:1326
 #, c-format
 msgid "inconsistent header lines %d and %d"
-msgstr ""
+msgstr "Inkonsistente Kopfzeilen %d und %d."
 
 #: apply.c:1498
 #, c-format
 msgid "recount: unexpected line: %.*s"
 msgstr "recount: unerwartete Zeile: %.*s"
 
 #: apply.c:1567
 #, c-format
 msgid "patch fragment without header at line %d: %.*s"
@@ -1528,27 +1528,27 @@ msgstr "LF würde in %s durch CRLF ersetzt werden."
 
 #: date.c:116
 msgid "in the future"
 msgstr "in der Zukunft"
 
 #: date.c:122 date.c:129 date.c:136 date.c:143 date.c:149 date.c:156 date.c:167
 #: date.c:175 date.c:180
 msgid "%"
 msgid_plural "%"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%"
+msgstr[1] "%"
 
 #. TRANSLATORS: "%s" is "<n> years"
 #: date.c:170
 msgid "%s, %"
 msgid_plural "%s, %"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%s, %"
+msgstr[1] "%s, %"
 
 #: diffcore-order.c:24
 #, c-format
 msgid "failed to read orderfile '%s'"
 msgstr "Fehler beim Lesen der Reihenfolgedatei '%s'."
 
 #: diffcore-rename.c:536
 msgid "Performing inexact rename detection"
 msgstr "Führe Erkennung für ungenaue Umbenennung aus"
@@ -1890,53 +1890,50 @@ msgid ""
 msgstr ""
 "'%s' scheint ein git-Befehl zu sein, konnte aber\n"
 "nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?"
 
 #: help.c:336
 msgid "Uh oh. Your system reports no Git commands at all."
 msgstr "Uh oh. Keine Git-Befehle auf Ihrem System vorhanden."
 
 #: help.c:358
-#, fuzzy, c-format
+#, c-format
 msgid "WARNING: You called a Git command named '%s', which does not exist."
-msgstr ""
-"Warnung: Sie haben den nicht existierenden Git-Befehl '%s' ausgeführt.\n"
-"Setze fort unter der Annahme, dass Sie '%s' gemeint haben."
+msgstr "WARNUNG: Sie haben Git-Befehl '%s' ausgeführt, welcher nicht existiert."
 
 #: help.c:363
 #, c-format
 msgid "Continuing under the assumption that you meant '%s'."
-msgstr ""
+msgstr "Setze fort unter der Annahme, dass Sie '%s' meinten."
 
 #: help.c:368
 #, c-format
 msgid "Continuing in %0.1f seconds, assuming that you meant '%s'."
-msgstr ""
+msgstr "Setze in %0.1f Sekunden fort unter der Annahme, dass Sie '%s' meinten."
 
 #: help.c:376
 #, c-format
 msgid "git: '%s' is not a git command. See 'git --help'."
 msgstr "git: '%s' ist kein Git-Befehl. Siehe 'git --help'."
 
 #: help.c:380
 msgid ""
 "\n"
 "The most similar command is"
 msgid_plural ""
 "\n"
 "The most similar commands are"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "\nDer ähnlichste Befehl ist"
+msgstr[1] "\nDie ähnlichsten Befehle sind"
 
 #: help.c:395
-#, fuzzy
 msgid "git version [<options>]"
-msgstr "git column [<Optionen>]"
+msgstr "git version [<Optionen>]"
 
 #: help.c:456
 #, c-format
 msgid "%s: %s - %s"
 msgstr "%s: %s - %s"
 
 #: help.c:460
 msgid ""
 "\n"
@@ -3361,21 +3358,21 @@ msgstr ""
 "Ausführung erfolgreich: %s\n"
 "Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
 "Führen Sie dann aus:\n"
 "\n"
 "  git rebase --continue\n"
 "\n"
 
 #: sequencer.c:1925
-#, fuzzy, c-format
+#, c-format
 msgid "Applied autostash.\n"
-msgstr "Automatischen Stash angewendet."
+msgstr "Automatischen Stash angewendet.\n"
 
 #: sequencer.c:1937
 #, c-format
 msgid "cannot store %s"
 msgstr "kann %s nicht speichern"
 
 #: sequencer.c:1940 git-rebase.sh:173
 #, c-format
 msgid ""
@@ -3649,21 +3646,21 @@ msgstr "Konnte Eintrag '%s' nicht aus .gitmodules entfernen"
 #: submodule.c:126
 msgid "staging updated .gitmodules failed"
 msgstr "Konnte aktualisierte .gitmodules-Datei nicht zum Commit vormerken"
 
 #: submodule.c:165
 msgid "negative values not allowed for submodule.fetchJobs"
 msgstr "Negative Werte für submodule.fetchJobs nicht erlaubt"
 
 #: submodule.c:376
-#, fuzzy, c-format
+#, c-format
 msgid "in unpopulated submodule '%s'"
-msgstr "Überspringe Submodul '%s'"
+msgstr "In nicht ausgechecktem Submodul '%s'."
 
 #: submodule.c:407
 #, c-format
 msgid "Pathspec '%s' is in submodule '%.*s'"
 msgstr "Pfadspezifikation '%s' befindet sich in Submodul '%.*s'"
 
 #: submodule.c:1337
 #, c-format
 msgid "'%s' not recognized as a git repository"
@@ -4330,23 +4327,23 @@ msgstr "neue Commits, "
 #: wt-status.c:374
 msgid "modified content, "
 msgstr "geänderter Inhalt, "
 
 #: wt-status.c:376
 msgid "untracked content, "
 msgstr "unversionierter Inhalt, "
 
 #: wt-status.c:821
-#, fuzzy, c-format
+#, c-format
 msgid "Your stash currently has %d entry"
 msgid_plural "Your stash currently has %d entries"
-msgstr[0] "Sie sind gerade beim Rebase."
-msgstr[1] "Sie sind gerade beim Rebase."
+msgstr[0] "Ihr Stash hat gerade %d Eintrag"
+msgstr[1] "Ihr Stash hat gerade %d Einträge"
 
 #: wt-status.c:853
 msgid "Submodules changed but not updated:"
 msgstr "Submodule geändert, aber nicht aktualisiert:"
 
 #: wt-status.c:855
 msgid "Submodule changes to be committed:"
 msgstr "Änderungen in Submodul zum Committen:"
 
@@ -4587,21 +4584,20 @@ msgstr "HEAD losgelöst von "
 #: wt-status.c:1586
 msgid "Not currently on any branch."
 msgstr "Im Moment auf keinem Branch."
 
 #: wt-status.c:1606
 msgid "Initial commit"
 msgstr "Initialer Commit"
 
 #: wt-status.c:1607
-#, fuzzy
 msgid "No commits yet"
-msgstr "Keine Commits geparst."
+msgstr "Noch keine Commits"
 
 #: wt-status.c:1621
 msgid "Untracked files"
 msgstr "Unversionierte Dateien"
 
 #: wt-status.c:1623
 msgid "Ignored files"
 msgstr "Ignorierte Dateien"
 
@@ -4674,21 +4670,20 @@ msgstr ""
 "nichts zu committen (benutzen Sie die Option -u, um unversionierte Dateien "
 "anzuzeigen)\n"
 
 #: wt-status.c:1668
 #, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
 
 #: wt-status.c:1780
-#, fuzzy
 msgid "No commits yet on "
-msgstr "Keine Befehle ausgeführt."
+msgstr "Noch keine Commits in "
 
 #: wt-status.c:1784
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Branch)"
 
 #: wt-status.c:1813 wt-status.c:1821
 msgid "behind "
 msgstr "hinterher "
 
@@ -4829,44 +4824,57 @@ msgstr "prüfen ob - auch fehlende - Dateien im Probelauf ignoriert werden"
 #: builtin/add.c:286 builtin/update-index.c:952
 msgid "(+/-)x"
 msgstr "(+/-)x"
 
 #: builtin/add.c:286 builtin/update-index.c:953
 msgid "override the executable bit of the listed files"
 msgstr "das \"ausführbar\"-Bit der aufgelisteten Dateien überschreiben"
 
 #: builtin/add.c:288
-#, fuzzy
 msgid "warn when adding an embedded repository"
-msgstr "ein Bare-Repository erstellen"
+msgstr "warnen wenn eingebettetes Repository hingefügt wird"
 
 #: builtin/add.c:303
 #, c-format
 msgid ""
 "You've added another git repository inside your current repository.\n"
 "Clones of the outer repository will not contain the contents of\n"
 "the embedded repository and will not know how to obtain it.\n"
 "If you meant to add a submodule, use:\n"
 "\n"
 "\tgit submodule add <url> %s\n"
 "\n"
 "If you added this path by mistake, you can remove it from the\n"
 "index with:\n"
 "\n"
 "\tgit rm --cached %s\n"
 "\n"
 "See \"git help submodule\" for more information."
 msgstr ""
+"Sie haben ein Git-Repository innerhalb ihres aktuellen Repositories hinzugefügt.\n"
+"Klone des äußeren Repositories werden die Inhalte des eingebetteten Repositories\n"
+"weder enthalten, noch wissen, wie diese zu beschaffen sind.\n"
+"Wenn Sie ein Submodul hinzufügen wollten, benutzen Sie:\n"
+"\n"
+"\tgit submodule add <URL> %s\n"
+"\n"
+"Wenn Sie diesen Pfad aus Versehen hinzugefügt haben, können Sie diesen mit\n"
+"\n"
+"\tgit rm --cached %s\n"
+"\n"
+"vom Index entfernen.\n"
+"\n"
+"Siehe \"git help submodule\" für weitere Informationen."
 
 #: builtin/add.c:331
-#, fuzzy, c-format
+#, c-format
 msgid "adding embedded git repository: %s"
-msgstr "--stdin erfordert ein Git-Repository"
+msgstr "Füge eingebettetes Repository hinzu: %s"
 
 #: builtin/add.c:349
 #, c-format
 msgid "Use -f if you really want to add them.\n"
 msgstr "Verwenden Sie -f wenn Sie diese wirklich hinzufügen möchten.\n"
 
 #: builtin/add.c:357
 msgid "adding files failed"
 msgstr "Hinzufügen von Dateien fehlgeschlagen"
@@ -4978,26 +4986,25 @@ msgstr ""
 
 #: builtin/am.c:1173
 #, c-format
 msgid "To restore the original branch and stop patching, run \"%s --abort\"."
 msgstr ""
 "Um den ursprünglichen Branch wiederherzustellen und die Anwendung der "
 "Patches abzubrechen, führen Sie \"%s --abort\" aus."
 
 #: builtin/am.c:1304
-#, fuzzy
 msgid "Patch is empty."
-msgstr "Der aktuelle Patch ist leer."
+msgstr "Patch ist leer."
 
 #: builtin/am.c:1370
-#, fuzzy, c-format
+#, c-format
 msgid "invalid ident line: %.*s"
-msgstr "Ungültige Identifikationszeile: %s"
+msgstr "Ungültige Identifikationszeile: %.*s"
 
 #: builtin/am.c:1392
 #, c-format
 msgid "unable to parse commit %s"
 msgstr "Konnte Commit '%s' nicht parsen."
 
 #: builtin/am.c:1586
 msgid "Repository lacks necessary blobs to fall back on 3-way merge."
 msgstr ""
@@ -5098,18 +5105,23 @@ msgstr ""
 "auslassen."
 
 #: builtin/am.c:1922
 msgid ""
 "You still have unmerged paths in your index.\n"
 "You should 'git add' each file with resolved conflicts to mark them as "
 "such.\n"
 "You might run `git rm` on a file to accept \"deleted by them\" for it."
 msgstr ""
+"Sie haben noch immer nicht zusammengeführte Pfade in Ihrem Index.\n"
+"Sie sollten 'git add' für jede Datei mit aufgelösten Konflikten ausführen,\n"
+"um diese als solche zu markieren.\n"
+"Sie können 'git rm' auf Dateien ausführen, um \"von denen gelöscht\" für\n"
+"diese zu akzeptieren."
 
 #: builtin/am.c:2031 builtin/am.c:2035 builtin/am.c:2047 builtin/reset.c:323
 #: builtin/reset.c:331
 #, c-format
 msgid "Could not parse object '%s'."
 msgstr "Konnte Objekt '%s' nicht parsen."
 
 #: builtin/am.c:2083
 msgid "failed to clean index"
@@ -6383,19 +6395,19 @@ msgid "Missing branch name; try -b"
 msgstr "Vermisse Branchnamen; versuchen Sie -b"
 
 #: builtin/checkout.c:1261
 msgid "invalid path specification"
 msgstr "ungültige Pfadspezifikation"
 
 #: builtin/checkout.c:1268
 #, c-format
 msgid "'%s' is not a commit and a branch '%s' cannot be created from it"
-msgstr ""
+msgstr "'%s' ist kein Commit und es kann kein Branch '%s' aus diesem erstellt werden."
 
 #: builtin/checkout.c:1272
 #, c-format
 msgid "git checkout: --detach does not take a path argument '%s'"
 msgstr "git checkout: --detach nimmt kein Pfad-Argument '%s'"
 
 #: builtin/checkout.c:1276
 msgid ""
 "git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
@@ -6695,19 +6707,19 @@ msgstr ""
 "die Historie eines Klons mit unvollständiger Historie (shallow) mittels\n"
 "Ausschluss eines Commits vertiefen"
 
 #: builtin/clone.c:124
 msgid "clone only one branch, HEAD or --branch"
 msgstr "nur einen Branch klonen, HEAD oder --branch"
 
 #: builtin/clone.c:126
 msgid "don't clone any tags, and make later fetches not to follow them"
-msgstr ""
+msgstr "keine Tags klonen, und auch bei späteren Abrufen nicht beachten"
 
 #: builtin/clone.c:128
 msgid "any cloned submodules will be shallow"
 msgstr "jedes geklonte Submodul mit unvollständiger Historie (shallow)"
 
 #: builtin/clone.c:129 builtin/init-db.c:485
 msgid "gitdir"
 msgstr ".git-Verzeichnis"
 
@@ -6906,20 +6918,20 @@ msgstr ""
 #: builtin/clone.c:1071
 msgid "--shallow-exclude is ignored in local clones; use file:// instead."
 msgstr ""
 "--shallow-exclude wird in lokalen Klonen ignoriert; benutzen Sie stattdessen "
 "file://"
 
 #: builtin/clone.c:1074
 msgid "source repository is shallow, ignoring --local"
 msgstr ""
-"Quelle ist ein Repository mit unvollständiger Historie (shallow),ignoriere --"
-"local"
+"Quelle ist ein Repository mit unvollständiger Historie (shallow),\n"
+"--local wird ignoriert"
 
 #: builtin/clone.c:1079
 msgid "--local is ignored"
 msgstr "--local wird ignoriert"
 
 #: builtin/clone.c:1083
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Weiß nicht wie %s zu klonen ist."
@@ -7324,21 +7336,20 @@ msgstr "Die Option -a kann nicht mit der Angabe von Pfaden verwendet werden."
 #: builtin/commit.c:1342 builtin/commit.c:1617
 msgid "show status concisely"
 msgstr "Status im Kurzformat anzeigen"
 
 #: builtin/commit.c:1344 builtin/commit.c:1619
 msgid "show branch information"
 msgstr "Branchinformationen anzeigen"
 
 #: builtin/commit.c:1346
-#, fuzzy
 msgid "show stash information"
-msgstr "Branchinformationen anzeigen"
+msgstr "Stashinformationen anzeigen"
 
 #: builtin/commit.c:1348
 msgid "version"
 msgstr "Version"
 
 #: builtin/commit.c:1348 builtin/commit.c:1621 builtin/push.c:530
 #: builtin/worktree.c:449
 msgid "machine-readable output"
 msgstr "maschinenlesbare Ausgabe"
@@ -7733,22 +7744,20 @@ msgid ""
 "#\temail = %s\n"
 msgstr ""
 "# Das ist Git's benutzerspezifische Konfiguraionsdatei.\n"
 "[user]\n"
 "# Bitte passen Sie die folgenden Zeilen an und kommentieren Sie diese aus:\n"
 "#\tname = %s\n"
 "#\temail = %s\n"
 
 #: builtin/config.c:499
-#, fuzzy
 msgid "--local can only be used inside a git repository"
-msgstr ""
-"Die Option --cached kann nicht außerhalb eines Repositories verwendet werden."
+msgstr "--local kann nur innerhalb eines Git-Repositories verwendet werden."
 
 #: builtin/config.c:621
 #, c-format
 msgid "cannot create configuration file %s"
 msgstr "Konnte Konfigurationsdatei '%s' nicht erstellen."
 
 #: builtin/config.c:633
 #, c-format
 msgid ""
@@ -8213,18 +8222,20 @@ msgstr "Verzeichnis"
 #: builtin/fetch.c:127
 msgid "prepend this to submodule path output"
 msgstr "dies an die Ausgabe der Submodul-Pfade voranstellen"
 
 #: builtin/fetch.c:130
 msgid ""
 "default for recursive fetching of submodules (lower priority than config "
 "files)"
 msgstr ""
+"Standard für die rekursive Anforderung von Submodulen (geringere Priorität\n"
+"als Konfigurationsdateien)"
 
 #: builtin/fetch.c:134 builtin/pull.c:212
 msgid "accept refs that update .git/shallow"
 msgstr "Referenzen, die .git/shallow aktualisieren, akzeptieren"
 
 #: builtin/fetch.c:135 builtin/pull.c:214
 msgid "refmap"
 msgstr "Refmap"
 
@@ -8883,21 +8894,20 @@ msgstr "--no-index oder --untracked können nicht mit Commits verwendet werden"
 msgid "unable to resolve revision: %s"
 msgstr "Konnte Commit nicht auflösen: %s"
 
 #: builtin/grep.c:1245 builtin/index-pack.c:1490
 #, c-format
 msgid "invalid number of threads specified (%d)"
 msgstr "ungültige Anzahl von Threads angegeben (%d)"
 
 #: builtin/grep.c:1250
-#, fuzzy
 msgid "no threads support, ignoring --threads"
-msgstr "keine Unterstützung von Threads, '%s' wird ignoriert"
+msgstr "keine Unterstützung von Threads, --threads wird ignoriert"
 
 #: builtin/grep.c:1281
 msgid "--open-files-in-pager only works on the worktree"
 msgstr ""
 "Die Option --open-files-in-pager kann nur innerhalb des "
 "Arbeitsverzeichnisses verwendet werden."
 
 #: builtin/grep.c:1304
 msgid "option not supported with --recurse-submodules."
@@ -10054,19 +10064,19 @@ msgstr "vollständige Pfadnamen verwenden"
 #: builtin/ls-tree.c:144
 msgid "list entire tree; not just current directory (implies --full-name)"
 msgstr ""
 "das gesamte Verzeichnis auflisten; nicht nur das aktuelle Verzeichnis "
 "(impliziert --full-name)"
 
 #: builtin/mailsplit.c:241
 #, c-format
 msgid "empty mbox: '%s'"
-msgstr ""
+msgstr "Leere mbox: '%s'"
 
 #: builtin/merge.c:47
 msgid "git merge [<options>] [<commit>...]"
 msgstr "git merge [<Optionen>] [<Commit>...]"
 
 #: builtin/merge.c:48
 msgid "git merge --abort"
 msgstr "git merge --abort"
 
@@ -11376,19 +11386,18 @@ msgstr "kann \"prune\" in precious-objects Repository nicht ausführen"
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Ungültiger Wert für %s: %s"
 
 #: builtin/pull.c:76
 msgid "git pull [<options>] [<repository> [<refspec>...]]"
 msgstr "git pull [<Optionen>] [<Repository> [<Refspec>...]]"
 
 #: builtin/pull.c:124
-#, fuzzy
 msgid "control for recursive fetching of submodules"
 msgstr "rekursive Anforderungen von Submodulen kontrollieren"
 
 #: builtin/pull.c:128
 msgid "Options related to merging"
 msgstr "Optionen bezogen auf Merge"
 
 #: builtin/pull.c:131
 msgid "incorporate changes by rebasing rather than merging"
@@ -11553,19 +11562,19 @@ msgstr ""
 msgid "Cannot merge multiple branches into empty head."
 msgstr "Kann nicht mehrere Branches in einen leeren Branch zusammenführen."
 
 #: builtin/pull.c:901
 msgid "Cannot rebase onto multiple branches."
 msgstr "Kann Rebase nicht auf mehrere Branches ausführen."
 
 #: builtin/pull.c:908
 msgid "cannot rebase with locally recorded submodule modifications"
-msgstr ""
+msgstr "Kann Rebase nicht mit lokal aufgezeichneten Änderungen in Submodulen ausführen."
 
 #: builtin/push.c:17
 msgid "git push [<options>] [<repository> [<refspec>...]]"
 msgstr "git push [<Optionen>] [<Repository> [<Refspec>...]]"
 
 #: builtin/push.c:90
 msgid "tag shorthand without <tag>"
 msgstr "Kurzschrift für Tag ohne <Tag>"
 
@@ -12620,21 +12629,20 @@ msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
 "gleiches wie oben, aber die Speichergröße anstatt der\n"
 "Anzahl der Einträge limitieren"
 
 #: builtin/repack.c:194
 msgid "limits the maximum delta depth"
 msgstr "die maximale Delta-Tiefe limitieren"
 
 #: builtin/repack.c:196
-#, fuzzy
 msgid "limits the maximum number of threads"
-msgstr "die maximale Delta-Tiefe limitieren"
+msgstr "maximale Anzahl von Threads limitieren"
 
 #: builtin/repack.c:198
 msgid "maximum size of each packfile"
 msgstr "maximale Größe für jede Paketdatei"
 
 #: builtin/repack.c:200
 msgid "repack objects in packs marked with .keep"
 msgstr ""
 "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
@@ -14946,21 +14954,20 @@ msgstr "Speicherte Arbeitsverzeichnis und Index-Status $stash_msg"
 msgid "Cannot remove worktree changes"
 msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
 
 #: git-stash.sh:474
 #, sh-format
 msgid "unknown option: $opt"
 msgstr "unbekannte Option: $opt"
 
 #: git-stash.sh:487
-#, fuzzy
 msgid "No stash entries found."
-msgstr "Kein Stash-Eintrag gefunden."
+msgstr "Keine Stash-Einträge gefunden."
 
 #: git-stash.sh:494
 #, sh-format
 msgid "Too many revisions specified: $REV"
 msgstr "Zu viele Commits angegeben: $REV"
 
 #: git-stash.sh:509
 #, sh-format
 msgid "$reference is not a valid reference"
@@ -14987,34 +14994,32 @@ msgstr "Kann \"stash\" nicht anwenden, solang ein Merge im Gange ist"
 #: git-stash.sh:568
 msgid "Conflicts in index. Try without --index."
 msgstr "Konflikte im Index. Versuchen Sie es ohne --index."
 
 #: git-stash.sh:570
 msgid "Could not save index tree"
 msgstr "Konnte Index-Verzeichnis nicht speichern"
 
 #: git-stash.sh:579
-#, fuzzy
 msgid "Could not restore untracked files from stash entry"
-msgstr "Konnte unversionierte Dateien vom Stash nicht wiederherstellen"
+msgstr "Konnte unversionierte Dateien vom Stash-Eintrag nicht wiederherstellen."
 
 #: git-stash.sh:604
 msgid "Cannot unstage modified files"
 msgstr "Kann geänderte Dateien nicht aus dem Index entfernen"
 
 #: git-stash.sh:619
 msgid "Index was not unstashed."
 msgstr "Index wurde nicht aus dem Stash zurückgeladen."
 
 #: git-stash.sh:633
-#, fuzzy
 msgid "The stash entry is kept in case you need it again."
-msgstr "Der Stash wird behalten, im Falle Sie benötigen diesen nochmal."
+msgstr "Der Stash-Eintrag wird behalten, im Falle Sie benötigen diesen nochmal."
 
 #: git-stash.sh:642
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Gelöscht ${REV} ($s)"
 
 #: git-stash.sh:643
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
@@ -16593,19 +16598,19 @@ msgstr "Der erforderliche SMTP-Server ist nicht korrekt definiert."
 
 #: git-send-email.perl:1411
 #, perl-format
 msgid "Server does not support STARTTLS! %s"
 msgstr "Server unterstützt kein STARTTLS! %s"
 
 #: git-send-email.perl:1416 git-send-email.perl:1420
 #, perl-format
 msgid "STARTTLS failed! %s"
-msgstr ""
+msgstr "STARTTLS fehlgeschlagen! %s"
 
 #: git-send-email.perl:1430
 msgid "Unable to initialize SMTP properly. Check config and use --smtp-debug."
 msgstr ""
 "Konnte SMTP nicht korrekt initialisieren. Bitte prüfen Sie Ihre "
 "Konfiguration\n"
 "und benutzen Sie --smtp-debug."
 
 #: git-send-email.perl:1448
-- 
2.14.0.rc0.284.gd933b75aa


^ permalink raw reply related	[relevance 2%]

* Re: [PATCH/RFC] commit-template: improve readability of commit template
  2017-06-28 13:04  0%       ` Kaartic Sivaraam
@ 2017-06-28 14:50  0%         ` Kaartic Sivaraam
  0 siblings, 0 replies; 200+ results
From: Kaartic Sivaraam @ 2017-06-28 14:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

I might have been ignorant about something about git in my reply in the
previous email (found below). In that case, please enlighten me.

On Wed, 2017-06-28 at 18:34 +0530, Kaartic Sivaraam wrote:
> On Tue, 2017-06-27 at 10:56 -0700, Junio C Hamano wrote:
> > Kaartic Sivaraam <kaarticsivaraam91196@gmail.com> writes:
> > > I thought it's not good to trade-off readability for vertical
> > > space
> > > as
> > > the ultimate aim of the commit template (at least to me) is to
> > > convey
> > > information to the user about the commit that he's going to make.
> > > For
> > > which, I thought it made more sense to improve it's readability
> > > by
> > > adding new lines between different sections rather than constrain
> > > the
> > > output within a few lines.
> > 
> > You have to be careful when making a trade-off argument.  It
> > depends
> > on how familiar you already are with the presentation.  Those who
> > are/got used to the order of things that come, they will know there
> > is extra information when the block of lines are longer than usual
> > without reading every character and then their eyes are guided to
> > read what is extra, without having to waste precious screen real
> > estate.  Nobody will _stay_ a new user who is not yet familiar with
> > the everyday output.
> > 
> 
> You're right. I didn't consider the fact that experienced users would
> be affected as a result of this change, sorry about that. I thought,
> making this change would help the new users who would possibly find
> the
> commit template to be congested and let experienced users to get
> accustomed to this new output format. I thought this change would be
> a
> win-win (at least after people get accustomed to the new
> formatting). 
> 
> In case screen real estate is considered more important here, no
> issues. I'll drop that part of the change, happily.
> 
> > > I actually didn't think of modifying that in order to keep it in
> > > line
> > > with the output of `git status`.
> > 
> > I was (and still am) assuming that if we make this change to "git
> > commit", we should make matching change to "git status" as a given.
> 
> I get it now. In that case, I don't think making the change would be
> a
> good choice for the following reasons,
> 
>     * I think vertical spacing matters more in the output printed to
> a
>     console.
>     * I myself find it odd to add a new line below the branch
>     information possibly because I'm too accustomed to it's current
>     output.
> 
> I tried adding the new line, it seemed to be too spacious. It might
> be
> just me in this case.
> 
> > > Further, to me, adding *this* new line
> > > before the "Changes not staged for commit" (or something in it's
> > > place)
> > > seems to be wasting some vertical space ...
> > 
> > I think it is in line with your original reasoning why you wanted
> > these extra blank lines to separate blocks of different kinds of
> > information:
> > 
> >  - "Please do this" instruction at the beginning
> >  - Make sure you know the default is --only, not --include
> >  - By the way you are committing for that person, not you
> >  - This change is being committed on that branch
> >  - Here are the changes that are already in the index
> >  - Here are the changes that are not in the index
> >  - Here are untracked files
> > 
> > Lack of a blank between the fourth block and the fifth block [*1*]
> > makes it somewhat inconsistent, doesn't it?
> > 
> 
> It does, for the given set of blocks. I didn't find it inconsistent
> as
> I thought the separate blocks as follows,
> 
>  - "Please do this" instruction at the beginning
>  - Make sure you know the default is --only, not --include
>  - By the way you are committing for that person, not you
>  - Status of repository (git status)
> 
> > [Footnote]
> > 
> > *1* Yes, we should think about removing the optional second block,
> >     as I think that it outlived its usefulness; if we are to do so,
> >     these become the third and the fourth blocks.
> 
> If I interpreted your previous email correctly, I thought we were
> doing
> it!
> 
> I'll send a "typical" patch as a follow-up of this mail.
> 


^ permalink raw reply	[relevance 0%]

* Re: [PATCH/RFC] commit-template: improve readability of commit template
  2017-06-27 17:56  4%     ` Junio C Hamano
@ 2017-06-28 13:04  0%       ` Kaartic Sivaraam
  2017-06-28 14:50  0%         ` Kaartic Sivaraam
  0 siblings, 1 reply; 200+ results
From: Kaartic Sivaraam @ 2017-06-28 13:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Tue, 2017-06-27 at 10:56 -0700, Junio C Hamano wrote:
> Kaartic Sivaraam <kaarticsivaraam91196@gmail.com> writes:
> > I thought it's not good to trade-off readability for vertical space
> > as
> > the ultimate aim of the commit template (at least to me) is to
> > convey
> > information to the user about the commit that he's going to make.
> > For
> > which, I thought it made more sense to improve it's readability by
> > adding new lines between different sections rather than constrain
> > the
> > output within a few lines.
> 
> You have to be careful when making a trade-off argument.  It depends
> on how familiar you already are with the presentation.  Those who
> are/got used to the order of things that come, they will know there
> is extra information when the block of lines are longer than usual
> without reading every character and then their eyes are guided to
> read what is extra, without having to waste precious screen real
> estate.  Nobody will _stay_ a new user who is not yet familiar with
> the everyday output.
> 
You're right. I didn't consider the fact that experienced users would
be affected as a result of this change, sorry about that. I thought,
making this change would help the new users who would possibly find the
commit template to be congested and let experienced users to get
accustomed to this new output format. I thought this change would be a
win-win (at least after people get accustomed to the new formatting). 

In case screen real estate is considered more important here, no
issues. I'll drop that part of the change, happily.

> > I actually didn't think of modifying that in order to keep it in
> > line
> > with the output of `git status`.
> 
> I was (and still am) assuming that if we make this change to "git
> commit", we should make matching change to "git status" as a given.
I get it now. In that case, I don't think making the change would be a
good choice for the following reasons,

    * I think vertical spacing matters more in the output printed to a
    console.
    * I myself find it odd to add a new line below the branch
    information possibly because I'm too accustomed to it's current
    output.

I tried adding the new line, it seemed to be too spacious. It might be
just me in this case.

> > Further, to me, adding *this* new line
> > before the "Changes not staged for commit" (or something in it's
> > place)
> > seems to be wasting some vertical space ...
> 
> I think it is in line with your original reasoning why you wanted
> these extra blank lines to separate blocks of different kinds of
> information:
> 
>  - "Please do this" instruction at the beginning
>  - Make sure you know the default is --only, not --include
>  - By the way you are committing for that person, not you
>  - This change is being committed on that branch
>  - Here are the changes that are already in the index
>  - Here are the changes that are not in the index
>  - Here are untracked files
> 
> Lack of a blank between the fourth block and the fifth block [*1*]
> makes it somewhat inconsistent, doesn't it?
> 
It does, for the given set of blocks. I didn't find it inconsistent as
I thought the separate blocks as follows,

 - "Please do this" instruction at the beginning
 - Make sure you know the default is --only, not --include
 - By the way you are committing for that person, not you
 - Status of repository (git status)

> [Footnote]
> 
> *1* Yes, we should think about removing the optional second block,
>     as I think that it outlived its usefulness; if we are to do so,
>     these become the third and the fourth blocks.
If I interpreted your previous email correctly, I thought we were doing
it!

I'll send a "typical" patch as a follow-up of this mail.

-- 
Regards,
Kaartic Sivaraam <kaarticsivaraam91196@gmail.com>

^ permalink raw reply	[relevance 0%]

* Re: [PATCH/RFC] commit-template: improve readability of commit template
  @ 2017-06-27 17:56  4%     ` Junio C Hamano
  2017-06-28 13:04  0%       ` Kaartic Sivaraam
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2017-06-27 17:56 UTC (permalink / raw)
  To: Kaartic Sivaraam; +Cc: git

Kaartic Sivaraam <kaarticsivaraam91196@gmail.com> writes:

>> I personally do not find these new blank lines are necessary, and
>> this change wastes vertical screen real estate which is a limited
>> resource, but that may be just me.  I on the other hand do not think
>> the result of this patch is overly worse than the status quo, either.
>> 
> I thought it's not good to trade-off readability for vertical space as
> the ultimate aim of the commit template (at least to me) is to convey
> information to the user about the commit that he's going to make. For
> which, I thought it made more sense to improve it's readability by
> adding new lines between different sections rather than constrain the
> output within a few lines.

You have to be careful when making a trade-off argument.  It depends
on how familiar you already are with the presentation.  Those who
are/got used to the order of things that come, they will know there
is extra information when the block of lines are longer than usual
without reading every character and then their eyes are guided to
read what is extra, without having to waste precious screen real
estate.  Nobody will _stay_ a new user who is not yet familiar with
the everyday output.

>> If we were to go with this sparser output, I think we also should
>> give an extra blank line before and after the "HEAD detached from
>> cafebabe" message you would see:
>> 
>> 	$ git checkout HEAD^0
>> 	$ git commit --allow-empty -o
>> 
>> or "On branch blah" if you are on a branch.  I think your change
>> adds a blank before, but it does not have a separation before
>> "Changes not staged for commit" line.
>> 
> I actually didn't think of modifying that in order to keep it in line
> with the output of `git status`.

I was (and still am) assuming that if we make this change to "git
commit", we should make matching change to "git status" as a given.

> Further, to me, adding *this* new line
> before the "Changes not staged for commit" (or something in it's place)
> seems to be wasting some vertical space ...

I think it is in line with your original reasoning why you wanted
these extra blank lines to separate blocks of different kinds of
information:

 - "Please do this" instruction at the beginning
 - Make sure you know the default is --only, not --include
 - By the way you are committing for that person, not you
 - This change is being committed on that branch
 - Here are the changes that are already in the index
 - Here are the changes that are not in the index
 - Here are untracked files

Lack of a blank between the fourth block and the fifth block [*1*]
makes it somewhat inconsistent, doesn't it?


[Footnote]

*1* Yes, we should think about removing the optional second block,
    as I think that it outlived its usefulness; if we are to do so,
    these become the third and the fourth blocks.

^ permalink raw reply	[relevance 4%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-30 23:04  5%           ` Philip Oakley
@ 2017-05-31  0:02  5%             ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2017-05-31  0:02 UTC (permalink / raw)
  To: Philip Oakley; +Cc: Git List

"Philip Oakley" <philipoakley@iee.org> writes:

> From: "Junio C Hamano" <gitster@pobox.com>
>
> Thanks for the replies. Let's see if I've got it...
>
>> "Philip Oakley" <philipoakley@iee.org> writes:
>>
>>> If I now understand correctly, the merge process flow is:
>>>
>>> * canonicalise content (eol, smudge-clean, $id, renormalise, etc)
>>> * diff the content (internal, or GIT_EXTERNAL_DIFF)
>>> * apply the diff
>>> * if conflicts, only then use merge-driver/tool
>>>
>>> Would that be a correct interpretation?
>>
>> Not quite.  There are a lot more going on before any of those steps:
>>
>> * Find the common ancestor commit (which could be many).
>
> IIUC Git selects one of them, rather than all if there are many (which
> then may not be the optimum)

Not quite.  The interface to "git merge-$backend" can take more than
one and "git merge" frontend does pass them to the backend.  How
they are used depends on the backend.  The "resolve" one tries to
use all of them at once; the "recursive" one tries merge across them
to come up with a tree to be used as a single "virtual common
ancestor".  But details does not matter for the purpose of analysing
the case that triggered this discussion.

>>
>> * Walk the three trees (the common ancestor's, ours and theirs) in
>>   parallel, noticing what happened to each path.  Depending on what
>>   happened to the path in each branch, the merge may or may not
>>   "conflict" (e.g. when both sides added exactly the same contents
>>   to the same path, they are not counted as conflicting.  when we
>>   removed while they modified, they show as conflicting).
>
> I'm assuming here that this is the sha-oid comparison, and then
> checking the tree/blob names that match them. (the top tree not having
> a name). So here "conflict free" is that the sha-oids match.
>
> Also, I thnk this is saying that added or removed trees or blobs are
> in some sense are 'conflict free' (though still subject to rename/move
> detection etc). An added file/blob would be conflict free for merging
> into it's tree, yes?

After "recursive" figures out the renames, an addition that still
remains (i.e. not matched up with a deletion elsewhere) would be a
candidate to be added silently (except that D/F conflict can still
be diagnosed).

>> * For paths that are conflicting, feed the canonicalized content of
>>   the versions from common, ours and theirs to the file-level merge
>>   driver.
>
> So this is where any .gitattibutes settings come in, or is the merge
> driver after the diff step? (which could also be a user diff?)

I think you answered this yourself in your "Ok, I think I can see
how I was confused..." paragraph.

^ permalink raw reply	[relevance 5%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-30  0:52  5%         ` Junio C Hamano
@ 2017-05-30 23:04  5%           ` Philip Oakley
  2017-05-31  0:02  5%             ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Philip Oakley @ 2017-05-30 23:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List

From: "Junio C Hamano" <gitster@pobox.com>

Thanks for the replies. Let's see if I've got it...

> "Philip Oakley" <philipoakley@iee.org> writes:
>
>> If I now understand correctly, the merge process flow is:
>>
>> * canonicalise content (eol, smudge-clean, $id, renormalise, etc)
>> * diff the content (internal, or GIT_EXTERNAL_DIFF)
>> * apply the diff
>> * if conflicts, only then use merge-driver/tool
>>
>> Would that be a correct interpretation?
>
> Not quite.  There are a lot more going on before any of those steps:
>
> * Find the common ancestor commit (which could be many).

IIUC Git selects one of them, rather than all if there are many (which then 
may not be the optimum)

>
> * Walk the three trees (the common ancestor's, ours and theirs) in
>   parallel, noticing what happened to each path.  Depending on what
>   happened to the path in each branch, the merge may or may not
>   "conflict" (e.g. when both sides added exactly the same contents
>   to the same path, they are not counted as conflicting.  when we
>   removed while they modified, they show as conflicting).

I'm assuming here that this is the sha-oid comparison, and then checking the 
tree/blob names that match them. (the top tree not having a name). So here 
"conflict free" is that the sha-oids match.

Also, I thnk this is saying that added or removed trees or blobs are in some 
sense are 'conflict free' (though still subject to rename/move detection 
etc). An added file/blob would be conflict free for merging into it's tree, 
yes?

IIUC, the comparison is therefore using the in-repo sha-oids; 
unless --renormalise was given which will do a smudge-clean washing cycle 
and recomute fresh canonical sha-oids for the comparison (rather than doing 
it later).

>
> * For paths that are conflicting, feed the canonicalized content of
>   the versions from common, ours and theirs to the file-level merge
>   driver.

So this is where any .gitattibutes settings come in, or is the merge driver 
after the diff step? (which could also be a user diff?)

>        The builtin file-level merge driver takes two xdiff (one
>   between ancestor and ours, the other between ancestore and
>   theirs) and reconciles them to produce the result.  But that is
>   irrelevant in the context of "custom merge driver"; the builtin
>   one is skipped altogether and the custom contents merge driver
>   the user specified via the attributes is used instead.
>
> Notice that the second step above has no customization knobs.  Any
> path the second step deems not to conflict is "merged cleanly"
> without even triggering the "oops, ours and theirs did conflicting
> changes, to the content; let's see how the final content should look
> like" (aka the third step).  This is *not* because "Git knows the
> best"; it is merely that nobody felt the need for a mechanism to
> allow customizing the second step.
>
> And that is why I said you need a new customization mechanism if you
> want to affect the outcome of the scenario that started this thread.

Ok, I think I can see how I was confused between the "tree merge" (oid 
conflict detection) and the more usual (to users) "file merge" (line by 
line, etc.). I wasn't sure where to find that as someone relatively new to 
Git.

Thanks for the explanations.
--
Philip 


---
This email has been checked for viruses by AVG.
http://www.avg.com


^ permalink raw reply	[relevance 5%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-29 12:57 10%       ` Philip Oakley
@ 2017-05-30  0:52  5%         ` Junio C Hamano
  2017-05-30 23:04  5%           ` Philip Oakley
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2017-05-30  0:52 UTC (permalink / raw)
  To: Philip Oakley; +Cc: Git List

"Philip Oakley" <philipoakley@iee.org> writes:

> If I now understand correctly, the merge process flow is:
>
> * canonicalise content (eol, smudge-clean, $id, renormalise, etc)
> * diff the content (internal, or GIT_EXTERNAL_DIFF)
> * apply the diff
> * if conflicts, only then use merge-driver/tool
>
> Would that be a correct interpretation?

Not quite.  There are a lot more going on before any of those steps:

 * Find the common ancestor commit (which could be many).

 * Walk the three trees (the common ancestor's, ours and theirs) in
   parallel, noticing what happened to each path.  Depending on what
   happened to the path in each branch, the merge may or may not
   "conflict" (e.g. when both sides added exactly the same contents
   to the same path, they are not counted as conflicting.  when we
   removed while they modified, they show as conflicting).

 * For paths that are conflicting, feed the canonicalized content of
   the versions from common, ours and theirs to the file-level merge
   driver.  The builtin file-level merge driver takes two xdiff (one
   between ancestor and ours, the other between ancestore and
   theirs) and reconciles them to produce the result.  But that is
   irrelevant in the context of "custom merge driver"; the builtin
   one is skipped altogether and the custom contents merge driver
   the user specified via the attributes is used instead.

Notice that the second step above has no customization knobs.  Any
path the second step deems not to conflict is "merged cleanly"
without even triggering the "oops, ours and theirs did conflicting
changes, to the content; let's see how the final content should look
like" (aka the third step).  This is *not* because "Git knows the
best"; it is merely that nobody felt the need for a mechanism to
allow customizing the second step.

And that is why I said you need a new customization mechanism if you
want to affect the outcome of the scenario that started this thread.

^ permalink raw reply	[relevance 5%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-28 13:06  5%     ` Junio C Hamano
@ 2017-05-29 12:57 10%       ` Philip Oakley
  2017-05-30  0:52  5%         ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Philip Oakley @ 2017-05-29 12:57 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List

From: "Junio C Hamano" <gitster@pobox.com>
> "Philip Oakley" <philipoakley@iee.org> writes:
>
>>> So I do not think this is not limited to "new file".  Anything that
>>> a tree-level three-way merge would resolve cleanly without having to
>>> consult the content-level three-way merge will complete without
>>> consulting the merge.ours.driver; per-file content-level three-way
>>> merge driver (which is what merge=<drivername> mechanism lets you
>>> specify via the attributes mechanism) is not something you would
>>> want to use for this kind of thing.  It is purely for resolving the
>>> actual content-level conflicts.
>>>
>> That (that Git knows best) sounds just wrong.
>
> Don't twist my words.  I never said Git knows best.

The part I was responding to was "would resolve cleanly without having to
consult the content-level three-way merge will complete without
consulting the merge.ours.driver".

It was that lack of consultation (by git) of the putative merge-driver that 
was being noted.

The general misunderstanding, as I now see it, is the (false) expectation 
that a merge-driver would do the whole merge process.

It took a bit of digging through the documentation for me to find out just 
what the merge process appears to be. I'm sure that it obvious to those who 
have worked with git from the beginning and the previous patch flow process, 
but the merge process wasn't obvious to me, and various blogs and SO Q&A on 
the issue suggest the same for many others.

If I now understand correctly, the merge process flow is:

* canonicalise content (eol, smudge-clean, $id, renormalise, etc)
* diff the content (internal, or GIT_EXTERNAL_DIFF)
* apply the diff
* if conflicts, only then use merge-driver/tool

Would that be a correct interpretation?



>
> The user-level merge driver is a mechanism to affect conflict level
> three-way merges.  The interface to the content level three-way
> merge driver feeds three versions of blobs and the driver is
> expected to give a merged result.  The interface as designed is
> incapable of passing "here is the common ancestor", "our side is
> missing" and "their side is this content".
>
> So if we want a mechanism that can affect the outcome of tree-level
> three-way merge, we need a _new_ mechanism.  The existing merge
> drivers that are written by end users (at least the ones written
> correctly to the spec, anyway) are not expecting to be called with
> "in our tree, there is no blob here", and trying to piggyback on it
> will break existing users.

Is an alternative to use the GIT_EXTERNAL_DIFF to create a nul diff, so no 
changes are applied (precious/sensitive file is left behind)? This would 
have no conflicts and no requirement for a merge-conflict driver.

--

Philip 


^ permalink raw reply	[relevance 10%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-28 10:24  5%   ` Philip Oakley
@ 2017-05-28 13:06  5%     ` Junio C Hamano
  2017-05-29 12:57 10%       ` Philip Oakley
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2017-05-28 13:06 UTC (permalink / raw)
  To: Philip Oakley; +Cc: Git List

"Philip Oakley" <philipoakley@iee.org> writes:

>> So I do not think this is not limited to "new file".  Anything that
>> a tree-level three-way merge would resolve cleanly without having to
>> consult the content-level three-way merge will complete without
>> consulting the merge.ours.driver; per-file content-level three-way
>> merge driver (which is what merge=<drivername> mechanism lets you
>> specify via the attributes mechanism) is not something you would
>> want to use for this kind of thing.  It is purely for resolving the
>> actual content-level conflicts.
>>
> That (that Git knows best) sounds just wrong.

Don't twist my words.  I never said Git knows best.  

The user-level merge driver is a mechanism to affect conflict level
three-way merges.  The interface to the content level three-way
merge driver feeds three versions of blobs and the driver is
expected to give a merged result.  The interface as designed is
incapable of passing "here is the common ancestor", "our side is
missing" and "their side is this content".

So if we want a mechanism that can affect the outcome of tree-level
three-way merge, we need a _new_ mechanism.  The existing merge
drivers that are written by end users (at least the ones written
correctly to the spec, anyway) are not expecting to be called with
"in our tree, there is no blob here", and trying to piggyback on it
will break existing users.

^ permalink raw reply	[relevance 5%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-28  1:14  5% ` Junio C Hamano
@ 2017-05-28 10:24  5%   ` Philip Oakley
  2017-05-28 13:06  5%     ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Philip Oakley @ 2017-05-28 10:24 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List

From: "Junio C Hamano" <gitster@pobox.com>
> "Philip Oakley" <philipoakley@iee.org> writes:
>
>> The git book [1] and a few blog posts [2] show how to preserve files 
>> which
>> are in the current branch against changes that are on the branch being
>> merged in.
>>
>> e.g. (from [2])
>>
>> echo '<filemane> merge=ours' >> .gitattributes && # commit
>> git config --global merge.ours.driver true
>>
>> (test) $ git checkout demo
>> (demo) $ git merge -
>> # <filename> contents are not merged and the original retained.
>>
>>
>>
>> However what is not covered (at least in the documentation ) is the case
>> where the file to be ignored is not present on the current branch, but is
>> present on the branch to be merged in.
>
> Hmph.  Per-path 'ours' and 'theirs' kick in only after we decide to
> perform the content level three-way merge.  I wonder what would (not
> "should", but "would with the current code") happen, with the same
> attribute setting, if the file being merged were not changed by ours
> but modified by the side branch?  I suspect that we'd take the change
> made by the side branch.

Here the 'ours' strategy is defined by the user's config file merge driver 
list.

I'd understood it that once it was decided there was a merge to be performed 
(the repective blob oid's in the repo/index are different) that the problem 
of merging is then handed off to the declared merge driver.

>
>> Normal expectations would be that in such a case the new file from the
>> second parent branch would be added to the current branch.
>

The git-scm and blog posts suggest that the original is left in place at the 
%P path, the merge driver run, and its return values used to decide if the 
user has to go and resolve conflicts. By setting the driver to 'true', the 
result is then said to be that the current 'blob' (i.e. file) is accepted 
unchanged (in %P), so anything from the second parent blob was completely 
ignored.

However if we have the addition of a new file, I can't tell from the docs 
what should happen? Is this still a merge such that the merge driver is 
called, or is the added file accepted without recourse to its .gitattributes 
setting (surely that would be a bug).

Then assuming we have reached an external driver, and it wants to not add 
that very file that was added in the second parent branch, what does the %P 
path point to (/dev/null?) - in particular, shouldn't the docs say? (I've 
not tested, and one test is not proof)

It maybe that the user wants a merge driver that says "If I ever see a 
secret key or password, then remove the whole file", which (removing the 
file from the merge) is a currently undocumented process (if even possible).

> So I do not think this is not limited to "new file".  Anything that
> a tree-level three-way merge would resolve cleanly without having to
> consult the content-level three-way merge will complete without
> consulting the merge.ours.driver; per-file content-level three-way
> merge driver (which is what merge=<drivername> mechanism lets you
> specify via the attributes mechanism) is not something you would
> want to use for this kind of thing.  It is purely for resolving the
> actual content-level conflicts.
>
That (that Git knows best) sounds just wrong. If the user has set a file 
attribute strategy, why would we ignore it? We already have different 
internal strategies anyway, so how do we even know that the potential merge 
was conflict free if we have haven't checked its attribute type. Maybe I'm 
missing something.
--
Philip 


^ permalink raw reply	[relevance 5%]

* Re: mergetool: what to do about deleting precious files?
  2017-05-27 10:03  9% mergetool: what to do about deleting precious files? Philip Oakley
@ 2017-05-28  1:14  5% ` Junio C Hamano
  2017-05-28 10:24  5%   ` Philip Oakley
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2017-05-28  1:14 UTC (permalink / raw)
  To: Philip Oakley; +Cc: Git List

"Philip Oakley" <philipoakley@iee.org> writes:

> The git book [1] and a few blog posts [2] show how to preserve files which
> are in the current branch against changes that are on the branch being
> merged in.
>
> e.g. (from [2])
>
> echo '<filemane> merge=ours' >> .gitattributes && # commit
> git config --global merge.ours.driver true
>
> (test) $ git checkout demo
> (demo) $ git merge -
> # <filename> contents are not merged and the original retained.
>
>
>
> However what is not covered (at least in the documentation ) is the case
> where the file to be ignored is not present on the current branch, but is
> present on the branch to be merged in.

Hmph.  Per-path 'ours' and 'theirs' kick in only after we decide to
perform the content level three-way merge.  I wonder what would (not
"should", but "would with the current code") happen, with the same
attribute setting, if the file being merged were not changed by ours
but modified by the side branch?  I suspect that we'd take the change
made by the side branch.

> Normal expectations would be that in such a case the new file from the
> second parent branch would be added to the current branch.

So I do not think this is not limited to "new file".  Anything that
a tree-level three-way merge would resolve cleanly without having to
consult the content-level three-way merge will complete without
consulting the merge.ours.driver; per-file content-level three-way
merge driver (which is what merge=<drivername> mechanism lets you
specify via the attributes mechanism) is not something you would
want to use for this kind of thing.  It is purely for resolving the
actual content-level conflicts.


^ permalink raw reply	[relevance 5%]

* mergetool: what to do about deleting precious files?
@ 2017-05-27 10:03  9% Philip Oakley
  2017-05-28  1:14  5% ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Philip Oakley @ 2017-05-27 10:03 UTC (permalink / raw)
  To: Git List

The git book [1] and a few blog posts [2] show how to preserve files which
are in the current branch against changes that are on the branch being
merged in.

e.g. (from [2])

echo '<filemane> merge=ours' >> .gitattributes && # commit
git config --global merge.ours.driver true

(test) $ git checkout demo
(demo) $ git merge -
# <filename> contents are not merged and the original retained.



However what is not covered (at least in the documentation ) is the case
where the file to be ignored is not present on the current branch, but is
present on the branch to be merged in.

Normal expectations would be that in such a case the new file from the
second parent branch would be added to the current branch.

Is there an easy way to use the current mergedriver mechanism to make this
new file from the second parent 'go away' - does one have to delete output
path (%P) or what? (or is this just a documenation issue?) [3]


Inspired by SO Q&A
https://stackoverflow.com/questions/44131926/git-merge-remove-unnecessary-file-folder/44138354#44138354
"
git merge
I'm trying to merge my dev branch to master, but I don't want to merge some
of the files/folders to master branch, because it is not needed now on
Master."


Any suggestions for a simple merge driver to avoid merging and commiting
such precious files from the second parent at merge time?
--
Philip

[1]
http://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#Merge-Strategies
[2]
https://medium.com/@porteneuve/how-to-make-git-preserve-specific-files-while-merging-18c92343826b
[3]
https://git-scm.com/docs/gitattributes #Defining a custom merge driver:
"The merge driver can learn the pathname in which the merged result will be
stored via placeholder %P."


^ permalink raw reply	[relevance 9%]

* [PATCH v3 48/53] merge: convert checkout_fast_forward to struct object_id
    2017-05-06 22:09  6% ` [PATCH v3 05/53] builtin/prune: convert to struct object_id brian m. carlson
@ 2017-05-06 22:10  4% ` brian m. carlson
  1 sibling, 0 replies; 200+ results
From: brian m. carlson @ 2017-05-06 22:10 UTC (permalink / raw)
  To: git
  Cc: Michael Haggerty, Jonathan Tan, Stefan Beller, Jeff King,
	Nguyễn Thái Ngọc Duy, Brandon Williams

Converting checkout_fast_forward is required to convert
parse_tree_indirect.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/merge.c | 4 ++--
 builtin/pull.c  | 4 ++--
 cache.h         | 4 ++--
 merge.c         | 8 ++++----
 sequencer.c     | 2 +-
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index f11b5f3de..5ea7f7da9 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1372,8 +1372,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(head_commit->object.oid.hash,
-					  commit->object.oid.hash,
+		if (checkout_fast_forward(&head_commit->object.oid,
+					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
 			goto done;
diff --git a/builtin/pull.c b/builtin/pull.c
index 2ffb6569a..318c273eb 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -523,7 +523,7 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0))
+	if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -839,7 +839,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
+		if (checkout_fast_forward(&orig_head, &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index e1f0e182a..8862510f9 100644
--- a/cache.h
+++ b/cache.h
@@ -2198,8 +2198,8 @@ struct commit_list;
 int try_merge_command(const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const unsigned char *from,
-			  const unsigned char *to,
+int checkout_fast_forward(const struct object_id *from,
+			  const struct object_id *to,
 			  int overwrite_ignore);
 
 
diff --git a/merge.c b/merge.c
index 04ee5fc91..b0cffe16f 100644
--- a/merge.c
+++ b/merge.c
@@ -44,8 +44,8 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	return ret;
 }
 
-int checkout_fast_forward(const unsigned char *head,
-			  const unsigned char *remote,
+int checkout_fast_forward(const struct object_id *head,
+			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
 	struct tree *trees[MAX_UNPACK_TREES];
@@ -79,10 +79,10 @@ int checkout_fast_forward(const unsigned char *head,
 	opts.fn = twoway_merge;
 	setup_unpack_trees_porcelain(&opts, "merge");
 
-	trees[nr_trees] = parse_tree_indirect(head);
+	trees[nr_trees] = parse_tree_indirect(head->hash);
 	if (!trees[nr_trees++])
 		return -1;
-	trees[nr_trees] = parse_tree_indirect(remote);
+	trees[nr_trees] = parse_tree_indirect(remote->hash);
 	if (!trees[nr_trees++])
 		return -1;
 	for (i = 0; i < nr_trees; i++) {
diff --git a/sequencer.c b/sequencer.c
index 9ca352ac7..dcc56a2b6 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -382,7 +382,7 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf err = STRBUF_INIT;
 
 	read_cache();
-	if (checkout_fast_forward(from->hash, to->hash, 1))
+	if (checkout_fast_forward(from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));

^ permalink raw reply related	[relevance 4%]

* [PATCH v3 05/53] builtin/prune: convert to struct object_id
  @ 2017-05-06 22:09  6% ` brian m. carlson
  2017-05-06 22:10  4% ` [PATCH v3 48/53] merge: convert checkout_fast_forward " brian m. carlson
  1 sibling, 0 replies; 200+ results
From: brian m. carlson @ 2017-05-06 22:09 UTC (permalink / raw)
  To: git
  Cc: Michael Haggerty, Jonathan Tan, Stefan Beller, Jeff King,
	Nguyễn Thái Ngọc Duy, Brandon Williams

Convert the sole instance of unsigned char [20] to struct object_id.
cmd_prune is a caller of parse_object, which we will convert later.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/prune.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/prune.c b/builtin/prune.c
index 42633e0c6..96dca7d58 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -123,11 +123,11 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 		die(_("cannot prune in a precious-objects repo"));
 
 	while (argc--) {
-		unsigned char sha1[20];
+		struct object_id oid;
 		const char *name = *argv++;
 
-		if (!get_sha1(name, sha1)) {
-			struct object *object = parse_object_or_die(sha1, name);
+		if (!get_oid(name, &oid)) {
+			struct object *object = parse_object_or_die(oid.hash, name);
 			add_pending_object(&revs, object, "");
 		}
 		else

^ permalink raw reply related	[relevance 6%]

* [PATCH v2 48/53] merge: convert checkout_fast_forward to struct object_id
    2017-05-01  2:28  6% ` [PATCH v2 05/53] builtin/prune: convert to struct object_id brian m. carlson
@ 2017-05-01  2:29  4% ` brian m. carlson
  1 sibling, 0 replies; 200+ results
From: brian m. carlson @ 2017-05-01  2:29 UTC (permalink / raw)
  To: git
  Cc: Michael Haggerty, Stefan Beller, Jeff King,
	Nguyễn Thái Ngọc Duy

Converting checkout_fast_forward is required to convert
parse_tree_indirect.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/merge.c | 4 ++--
 builtin/pull.c  | 4 ++--
 cache.h         | 4 ++--
 merge.c         | 8 ++++----
 sequencer.c     | 2 +-
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index f11b5f3de..5ea7f7da9 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1372,8 +1372,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(head_commit->object.oid.hash,
-					  commit->object.oid.hash,
+		if (checkout_fast_forward(&head_commit->object.oid,
+					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
 			goto done;
diff --git a/builtin/pull.c b/builtin/pull.c
index 2ffb6569a..318c273eb 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -523,7 +523,7 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0))
+	if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -839,7 +839,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
+		if (checkout_fast_forward(&orig_head, &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index e1f0e182a..8862510f9 100644
--- a/cache.h
+++ b/cache.h
@@ -2198,8 +2198,8 @@ struct commit_list;
 int try_merge_command(const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const unsigned char *from,
-			  const unsigned char *to,
+int checkout_fast_forward(const struct object_id *from,
+			  const struct object_id *to,
 			  int overwrite_ignore);
 
 
diff --git a/merge.c b/merge.c
index 04ee5fc91..b0cffe16f 100644
--- a/merge.c
+++ b/merge.c
@@ -44,8 +44,8 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	return ret;
 }
 
-int checkout_fast_forward(const unsigned char *head,
-			  const unsigned char *remote,
+int checkout_fast_forward(const struct object_id *head,
+			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
 	struct tree *trees[MAX_UNPACK_TREES];
@@ -79,10 +79,10 @@ int checkout_fast_forward(const unsigned char *head,
 	opts.fn = twoway_merge;
 	setup_unpack_trees_porcelain(&opts, "merge");
 
-	trees[nr_trees] = parse_tree_indirect(head);
+	trees[nr_trees] = parse_tree_indirect(head->hash);
 	if (!trees[nr_trees++])
 		return -1;
-	trees[nr_trees] = parse_tree_indirect(remote);
+	trees[nr_trees] = parse_tree_indirect(remote->hash);
 	if (!trees[nr_trees++])
 		return -1;
 	for (i = 0; i < nr_trees; i++) {
diff --git a/sequencer.c b/sequencer.c
index 68e032630..b295004af 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -382,7 +382,7 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf err = STRBUF_INIT;
 
 	read_cache();
-	if (checkout_fast_forward(from->hash, to->hash, 1))
+	if (checkout_fast_forward(from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));

^ permalink raw reply related	[relevance 4%]

* [PATCH v2 05/53] builtin/prune: convert to struct object_id
  @ 2017-05-01  2:28  6% ` brian m. carlson
  2017-05-01  2:29  4% ` [PATCH v2 48/53] merge: convert checkout_fast_forward " brian m. carlson
  1 sibling, 0 replies; 200+ results
From: brian m. carlson @ 2017-05-01  2:28 UTC (permalink / raw)
  To: git
  Cc: Michael Haggerty, Stefan Beller, Jeff King,
	Nguyễn Thái Ngọc Duy

Convert the sole instance of unsigned char [20] to struct object_id.
cmd_prune is a caller of parse_object, which we will convert later.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/prune.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/prune.c b/builtin/prune.c
index 42633e0c6..96dca7d58 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -123,11 +123,11 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 		die(_("cannot prune in a precious-objects repo"));
 
 	while (argc--) {
-		unsigned char sha1[20];
+		struct object_id oid;
 		const char *name = *argv++;
 
-		if (!get_sha1(name, sha1)) {
-			struct object *object = parse_object_or_die(sha1, name);
+		if (!get_oid(name, &oid)) {
+			struct object *object = parse_object_or_die(oid.hash, name);
 			add_pending_object(&revs, object, "");
 		}
 		else

^ permalink raw reply related	[relevance 6%]

* [PATCH 48/53] merge: convert checkout_fast_forward to struct object_id
    2017-04-23 21:34  6% ` [PATCH 05/53] builtin/prune: convert to struct object_id brian m. carlson
@ 2017-04-23 21:34  4% ` brian m. carlson
  1 sibling, 0 replies; 200+ results
From: brian m. carlson @ 2017-04-23 21:34 UTC (permalink / raw)
  To: git; +Cc: Michael Haggerty, Jeff King,
	Nguyễn Thái Ngọc Duy

Converting checkout_fast_forward is required to convert
parse_tree_indirect.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/merge.c | 4 ++--
 builtin/pull.c  | 4 ++--
 cache.h         | 4 ++--
 merge.c         | 8 ++++----
 sequencer.c     | 2 +-
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index f11b5f3de..5ea7f7da9 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1372,8 +1372,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 			goto done;
 		}
 
-		if (checkout_fast_forward(head_commit->object.oid.hash,
-					  commit->object.oid.hash,
+		if (checkout_fast_forward(&head_commit->object.oid,
+					  &commit->object.oid,
 					  overwrite_ignore)) {
 			ret = 1;
 			goto done;
diff --git a/builtin/pull.c b/builtin/pull.c
index 21e114ec0..f539c7f78 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -523,7 +523,7 @@ static int pull_into_void(const struct object_id *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head->hash, 0))
+	if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -839,7 +839,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
+		if (checkout_fast_forward(&orig_head, &curr_head, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index ba27595d5..552c44ef0 100644
--- a/cache.h
+++ b/cache.h
@@ -2188,8 +2188,8 @@ struct commit_list;
 int try_merge_command(const char *strategy, size_t xopts_nr,
 		const char **xopts, struct commit_list *common,
 		const char *head_arg, struct commit_list *remotes);
-int checkout_fast_forward(const unsigned char *from,
-			  const unsigned char *to,
+int checkout_fast_forward(const struct object_id *from,
+			  const struct object_id *to,
 			  int overwrite_ignore);
 
 
diff --git a/merge.c b/merge.c
index 04ee5fc91..b0cffe16f 100644
--- a/merge.c
+++ b/merge.c
@@ -44,8 +44,8 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 	return ret;
 }
 
-int checkout_fast_forward(const unsigned char *head,
-			  const unsigned char *remote,
+int checkout_fast_forward(const struct object_id *head,
+			  const struct object_id *remote,
 			  int overwrite_ignore)
 {
 	struct tree *trees[MAX_UNPACK_TREES];
@@ -79,10 +79,10 @@ int checkout_fast_forward(const unsigned char *head,
 	opts.fn = twoway_merge;
 	setup_unpack_trees_porcelain(&opts, "merge");
 
-	trees[nr_trees] = parse_tree_indirect(head);
+	trees[nr_trees] = parse_tree_indirect(head->hash);
 	if (!trees[nr_trees++])
 		return -1;
-	trees[nr_trees] = parse_tree_indirect(remote);
+	trees[nr_trees] = parse_tree_indirect(remote->hash);
 	if (!trees[nr_trees++])
 		return -1;
 	for (i = 0; i < nr_trees; i++) {
diff --git a/sequencer.c b/sequencer.c
index c673bb930..dfa44afa7 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -382,7 +382,7 @@ static int fast_forward_to(const struct object_id *to, const struct object_id *f
 	struct strbuf err = STRBUF_INIT;
 
 	read_cache();
-	if (checkout_fast_forward(from->hash, to->hash, 1))
+	if (checkout_fast_forward(from, to, 1))
 		return -1; /* the callee should have complained already */
 
 	strbuf_addf(&sb, _("%s: fast-forward"), _(action_name(opts)));

^ permalink raw reply related	[relevance 4%]

* [PATCH 05/53] builtin/prune: convert to struct object_id
  @ 2017-04-23 21:34  6% ` brian m. carlson
  2017-04-23 21:34  4% ` [PATCH 48/53] merge: convert checkout_fast_forward " brian m. carlson
  1 sibling, 0 replies; 200+ results
From: brian m. carlson @ 2017-04-23 21:34 UTC (permalink / raw)
  To: git; +Cc: Michael Haggerty, Jeff King,
	Nguyễn Thái Ngọc Duy

Convert the sole instance of unsigned char [20] to struct object_id.
cmd_prune is a caller of parse_object, which we will convert later.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/prune.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/builtin/prune.c b/builtin/prune.c
index 42633e0c6..96dca7d58 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -123,11 +123,11 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 		die(_("cannot prune in a precious-objects repo"));
 
 	while (argc--) {
-		unsigned char sha1[20];
+		struct object_id oid;
 		const char *name = *argv++;
 
-		if (!get_sha1(name, sha1)) {
-			struct object *object = parse_object_or_die(sha1, name);
+		if (!get_oid(name, &oid)) {
+			struct object *object = parse_object_or_die(oid.hash, name);
 			add_pending_object(&revs, object, "");
 		}
 		else

^ permalink raw reply related	[relevance 6%]

* RE: [PATCH] repack: respect gc.pid lock
  @ 2017-04-18 17:08  4%       ` David Turner
  0 siblings, 0 replies; 200+ results
From: David Turner @ 2017-04-18 17:08 UTC (permalink / raw)
  To: 'Jeff King'
  Cc: git@vger.kernel.org, christian.couder@gmail.com,
	mfick@codeaurora.org, jacob.keller@gmail.com

> -----Original Message-----
> From: Jeff King [mailto:peff@peff.net]
> Sent: Monday, April 17, 2017 11:42 PM
> To: David Turner <David.Turner@twosigma.com>
> Cc: git@vger.kernel.org; christian.couder@gmail.com; mfick@codeaurora.org;
> jacob.keller@gmail.com
> Subject: Re: [PATCH] repack: respect gc.pid lock
> 
> On Mon, Apr 17, 2017 at 11:29:18PM +0000, David Turner wrote:
> 
> > We saw this failure in the logs multiple  times (with three different
> > shas, while a gc was running):
> > April 12, 2017 06:45 -> ERROR -> 'git -c repack.writeBitmaps=true repack -A -d
> --pack-kept-objects' in [repo] failed:
> > fatal: packfile ./objects/pack/pack-[sha].pack cannot be accessed
> > Possibly some other repack was also running at the time as well.
> >
> > My colleague also saw it while manually doing gc (again while repacks
> > were likely to be running):
> 
> This is sort of a side question, but...why are you running other repacks alongside
> git-gc? It seems like you ought to be doing one or the other.
>
> I don't begrudge anybody with a complicated setup running their own set of gc
> commands, but I'd think you would want to do locking there, and disable auto-
> gc entirely. Otherwise you're going to get different results depending on who
> gc'd last.

That's what gitlab does, so you'll have to ask them why they do it that way.  
From https://gitlab.com/gitlab-org/gitlab-ce/issues/30939#note_27487981
 it looks like they may have intended to have a lock but not quite succeeded.
 
> > $ git gc --aggressive
> > Counting objects: 13800073, done.
> > Delta compression using up to 8 threads.
> > Compressing objects:  99% (11465846/11465971)
> > Compressing objects: 100% (11465971/11465971), done.
> > fatal: packfile [repo]/objects/pack/pack-[sha].pack cannot be accessed
> 
> OK, so this presumably happened during the writing phase. Which seems like the
> "a pack was closed, and we couldn't re-open it" problem we've seen before.
> 
> > We have a reasonable rlimit (64k soft limit), so that failure mode is
> > pretty unlikely.  I  think we should have had 20 or so packs -- not tens of
> thousands.
> > [...]
> > Do you have any idea why this would be happening other than the rlimit thing?
> 
> Yeah, that should be enough (you could double check the return of
> get_max_fd_limit() on your system if you wanted to be paranoid).
> 
> We also keep only a limited number of bytes mmap'd at one time. Normally we
> don't actually close packfiles when we release their mmap windows.
> But I think there is one path that might. When use_pack() maps a pack, if the
> entire pack fits in a single window, then we close it; this is due to d131b7afe
> (sha1_file.c: Don't retain open fds on small packs, 2011-03-02).
> 
> But if we ever unmap that window, now we have no handle to the pack.
> Normally on a 64-bit system this wouldn't happen at all, since the default
> core.packedGitLimit is 8GB there.

Aha, I missed that limit while messing around with the code.  That must be it.

> So if you have a few small packs and one very large pack (over 8GB), I think this
> could trigger. We may do the small-pack thing for some of them, and then the
> large pack forces us to drop the mmaps for some of the others. When we go
> back to access the small pack, we find it's gone.
> 
> One solution would be to bump core.packedGitLimit to something much higher
> (it's an mmap, so we're really just chewing up address space; it's up to the OS to
> decide when to load pages from disk and when to drop them).
>
> The other alternative is to disable the small-pack closing from d131b7afe. It
> might need to be configurable, or perhaps auto-tuned based on the fd limit.
> Linux systems tend to have generous descriptor limits, but I'm not sure we can
> rely on that. OTOH, it seems like the code to close descriptors when needed
> would take care of things. So maybe we should just revert d131b7afe entirely.

I definitely remember running into fd limits when processing very large numbers 
of packs at Twitter, but I don't recall the exact details.  Presumably, d131b7afe
was supposed to help with this, but in fact, it did not totally solve it. Perhaps 
we were doing something funny.  Adjusting the fd limits was the easy fix.

On 64-bit systems, I think core.packedGitLimit doesn't make a 
lot of sense. There is plenty of address space.  Why not use it?

For 32-bit systems, of course, address space is more precious.

I'll ask our git server administrator to adjust core.packedGitLimit
and turn repacks back on to see if that fixes the issue.

> The final thing I'd ask is whether you might be on a networked filesystem that
> would foil our usual "open descriptors mean packs don't go away" logic. But
> after having dug into the details above, I have a feeling the answer is simply that
> you have repositories >8GB.

Yes, our repo is >8GB, and no, it's not on a networked filesystem.

> And if that is the case, then yeah, your locking patch is definitely a band-aid. If
> you fetch and repack at the same time, you'll eventually see a racy failed fetch.

Fair enough.

^ permalink raw reply	[relevance 4%]

* Re: Git allow to unconditionaly remove files on other developer host
  2017-04-15 12:27  4% ` Johannes Sixt
@ 2017-04-15 12:53  0%   ` Konstantin Khomoutov
  0 siblings, 0 replies; 200+ results
From: Konstantin Khomoutov @ 2017-04-15 12:53 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, KES

On Sat, 15 Apr 2017 14:27:00 +0200
Johannes Sixt <j6t@kdbg.org> wrote:

> > That curious, but git allow to unconditionally delete files on
> > other developer host when he do `git pull`
[...]
> Know that Git regards everything mentioned in .gitignore as
> dispensible; IOW, by mentioning a file in .gitignore you actually
> give permission to remove the file if necessary. Git does not have a
> feature to say "ignore this file, but it is precious".

KES, you might also be interested in this recent thread [1].

1. http://public-inbox.org/git/CAPUVn2u0Uos2mT5+4ejj8m0okNK6XwerL6ce2miHfhtuEs-ZnQ@mail.gmail.com/

^ permalink raw reply	[relevance 0%]

* Re: Git allow to unconditionaly remove files on other developer host
  @ 2017-04-15 12:27  4% ` Johannes Sixt
  2017-04-15 12:53  0%   ` Konstantin Khomoutov
  0 siblings, 1 reply; 200+ results
From: Johannes Sixt @ 2017-04-15 12:27 UTC (permalink / raw)
  To: KES, git

Am 15.04.2017 um 13:36 schrieb KES:
> That curious, but git allow to unconditionally delete files on other developer host when he do `git pull`
>
> How to reproduce:
>
> 1. File should be ignored:
> echo "somefile" >> .gitignore
>
> 2. Add this ignored file into repository
> git add -f somefile
>
> 3. Push changes to origin
> git push
>
> 4. When other developer has also 'somefile' on his host and when he does
> git pull
>
> Content of hist local `somefile` file will be replaced by content pushed by first developer

This happens *only* if the other developers also have somefile mentioned 
in their .gitignore.

>
> EXPECTED: git should warn about that content will be replaced and do not pull/checkout until we force pull/checkout

If somefile is *not* mentioned in their .gitignore, the file is not 
removed and there is a warning.

Know that Git regards everything mentioned in .gitignore as dispensible; 
IOW, by mentioning a file in .gitignore you actually give permission to 
remove the file if necessary. Git does not have a feature to say "ignore 
this file, but it is precious".

-- Hannes


^ permalink raw reply	[relevance 4%]

* Re: [GSoC] Proposal: turn git-add--interactive.perl into a builtin
  2017-03-31  5:07  3%     ` Daniel Ferreira (theiostream)
@ 2017-03-31 19:06  0%       ` Daniel Ferreira (theiostream)
  0 siblings, 0 replies; 200+ results
From: Daniel Ferreira (theiostream) @ 2017-03-31 19:06 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Stefan Beller, Git Mailing List, Christian Couder

Well, Google requires me to have a draft on a Google Doc anyway for
the proposal, and I am unsure who exactly it will reach. Since it *is*
part of the discussion regarding my proposal, I suppose it is worth
posting here for anyone to comment:
https://docs.google.com/document/d/1dvF2PNRQvvZ351jCdKzOLs7tzaDqhR7ci7TDgzYQg9I/edit?usp=sharing.

-- Daniel.

On Fri, Mar 31, 2017 at 2:07 AM, Daniel Ferreira (theiostream)
<bnmvco@gmail.com> wrote:
> Hi Stefan & Johannes,
>
> Thank you for the precious feedback on the proposal. I don't see much
> sense in sending a full "v2" of it and have you read it all over
> again, so I'll just answer to your comments directly.
>
> Also, although the GSoC website allows me to send a "proposal draft"
> to you through the website, since I've already sent it here that
> shouldn't be necessary, correct? I intend to use it just to send the
> final thing.
>
> On Wed, Mar 29, 2017 at 9:01 PM, Johannes Schindelin
> <Johannes.Schindelin@gmx.de> wrote:
>> On Tue, 28 Mar 2017, Stefan Beller wrote:
>>
>>> On Sat, Mar 25, 2017 at 8:15 PM, Daniel Ferreira (theiostream)
>>> <bnmvco@gmail.com> wrote:
>>>
>>> > SYNOPSIS
>>> > There are many advantages to converting parts of git that are still
>>> > scripts to C builtins, among which execution speed, improved
>>> > compatibility and code deduplication.
>>>
>>> agreed.
>>
>> I would even add portability. But yeah, speed is a big thing. I am an
>> extensive user of `git add -p` (which is backed by
>> git-add--interactive.perl) and it is slow as molasses on Windows, just
>> because it is a Perl script (and the Perl interpreter needs to emulate
>> POSIX functionality that is frequently not even needed, such as: copying
>> all memory and reopening all file descriptors in a fork() call only to
>> exec() git.exe right away, tossing all of the diligently work into the
>> dustbin).
>
> Thanks for this example – it hadn't come to my mind since I don't use
> Git on Windows. I'll be sure to complement the synopsis with it. :)
>
>>
>>> > FEASIBILITY
>>> >
>>> > There was only one discussion regarding the feasibility of its porting
>>> > (https://public-inbox.org/git/CAP8UFD2PcBsU6=FK4OHVrB7E98ycohS_0pYcbCBar=of1HLx+Q@mail.gmail.com/).
>>> > It resulted in a consensus that doing it would be a task too large –
>>> > although interesting – for GSoC 2015 based on the amount of its lines
>>> > of code. It is, however, only a few lines larger than
>>> > git-rebase--interactive, which has been considered an appropriate
>>> > idea. As such, it looks like a possible project for three months of
>>> > full-time work.
>>>
>>> ok, it sounds a challenging project. (currently counting 1750 lines of
>>> code). Scrolling over the source code, there are quite a couple of
>>> functions, where the direct equivalent in C springs to mind.
>>>
>>> run_cmd_pipe -> see run-command.h
>>> unquote_path -> unquote_c_style ?
>>> refresh -> update_index_if_able()
>>> list_modified -> iterate over "const struct cache_entry *ce = active_cache[i];"
>
> Thank you for these functions. I don't think I will be able to specify
> them in detail as part of the projected timeline (e.g. "June 1:
> convert calls to refresh() to use update_index_if_able()") already
> because there is not enough time prior to the proposal deadline to
> study their behavior in detail, and I like to avoid talking about
> things I don't fully understand. Although I think I can cite them as
> examples for a thesis I had put elsewhere in the proposal that "Git
> APIs in Perl already have functional equivalents in C".
>
> Also, they will be great for my early investigation stage into
> git-add--interactive. :) Once more, thanks for having listed them.
>
>> Yes, I think it would be more important to acquaint oneself with the
>> idiosynchracies of Git's internal "API" than to get familiar with Perl:
>> interpreting what obscure Perl code does is something I would gladly do as
>> a mentor.
>
> That's really nice! I usually don't get stuck when trying to
> understand code in languages I'm not too well acquainted with, but I
> figured getting more familiar with Perl would speed development up.
> But it does make sense that this "prior to May 4" might be better
> invested learning about git's internals than Perl.
>
> Question: do you suggest any pending bugfix to git-add--interactive or
> to something related that might give some useful knowledge in advance?
> (for the pre-code period). My microproject involves playing with the
> dir_iterator interface, which is a great exercise in code refactoring
> but really does not teach me too much about Git's architecture.
>
> Even if you do not have an answer to this, I'm pretty sure I'll keep
> this commitment to submitting some patch series somehow related to
> git-add before GSoC begins, especially after this comment from
> Johannes.
>
>>
>>> > PROJECTED TIMELINE
>>> > - Prior to May 4
>>> > -- Refine my basic knowledge of Perl
>>> > -- Craft one or two small patches to some of Git's Perl components
>>> > (preferentially to git-add--interactive itself) to improve my
>>> > understanding of the language and of how Git's Perl scripts actually
>>> > work
>
> So yeah, I think this could be rewritten as:
>
> - Prior to May 4
> -- Craft two or three small patch series to git-add--interactive or
> related components to improve my understanding of Git's internal
> architecture, especially that related to git-add.
>
>>
>>> > - May 4 - May 30
>>> > -- Clarify implementation details with my mentor, and work on a more
>>> > detailed roadmap for the project
>>> > -- Investigate roughly how to replace command invocations from the
>>> > script with actual builtin functions; which Git APIs in Perl already
>>> > have functional equivalents in C; which parts will require a full
>>> > rewrite.
>>> There are different approaches for replacing functionality in another
>>> language. Examples:
>>> * Implement the functionality in C and then have a "flag-day" commit
>>>   783d7e865e (builtin-am: remove redirection to git-am.sh, 2015-08-04)
>>>   This only works when the whole functionality was replaced in prior commits
>>> * Implement partial functionality in C and call it via a helper function.
>>>   3604242f08 (submodule: port init from shell to C, 2016-04-15)
>>>   This works well for only partial conversions (the larger the thing to
>>>   convert the more appealing this is, as it gets code shipped early.)
>>>   When choosing this strategy, this part of the Project would be to
>>>   identify parts that could be ported on its own without much
>>>   additional glue-code.
>>
>> To offer my perspective: I strongly prefer the latter approach. Not only
>> does it yield earlier results, it also makes it substantially easier to
>> handle the project even if it should turn out to be a little larger than
>> just 3 months.
>
> I agree. I even think that the latter parts of this projected timeline
> imply a choice for the second approach.
>
> For now, Stefan's implementation in 3604242f08 (create a helper
> builtin command, call it from a script, do it to other functions until
> the whole script is replaced) seems the most natural way to do it. But
> sadly, I still do not have enough knowledge about the project to be
> able to specify in this proposal how (e.g. in what order) exactly I
> intend to "divide" the code to do this. But I'm sure the answer to
> this question will be clearer through contact with my mentor and with
> growing experience in the project.
>
>>
>>> > - May 30 - June 30 (start of coding period)
>>> > -- Define the architecture of the builtin within git (which
>>> > functions/interfaces will it have? where will its code reside?).
>>> > -- Implement a small subset of the builtin (to be defined with my
>>> > mentor) and glue it into the existing Perl script. Present this as a
>>> > first patch to get feedback early regarding the implementation and
>>> > avoid piling up mistakes early.
>>> > -- Do necessary changes based on this initial review.
>>> > -- Have roughly 1/3 of the script's functionality ported to C.
>>> >
>>> > - June 30 - July 28
>>> > -- Port the remainder of the script to a builtin.
>>> > -- Have a weekly roadmap, sending a part of the patch every 15 days to
>>> > the mailing list for review and to avoid massive commits by the end of
>>> > GSoC.
>>>
>>> yeah; send early, send often. ;)
>>
>> Even better: push multiple times a day to a public repository, say, on
>> GitHub. That allows for "Work In Progress" commits that not only serve as
>> a backup but also as transparent report what was done.
>
> Great idea. It can also be a good way to report my progress to my
> mentor. (I'll do my best to avoid "[WIP]" commits with barely any
> explanation).
>
> As for the "timeline", I think it can be improved by some better
> specification regarding the gradual process of the implementation
> opposed to switching from the script to a builtin all at once.
>
>>> > -- Apply suggestions from community reviews when possible; if not,
>>> > save them for doing toward the end of GSoC (see below).
>>>
>>> Please do not underestimate the discussion by community, finding
>>> consensus on list consumes a bit of time in some cases.
>> I agree with this statement. Ideally, the first patch series would be
>> ready to submit very soon into the project, something like 2 weeks (which
>> is another point in favor of the helper approach outlined by Stefan).
>> The smaller the patch series are, the more likely they will get in
>> quickly. And the easier is it to address reviewers' comments, because you
>> won't have to send out gazillion unchanged patches of a multi-dozen patch
>> series just to address one typo in one patch.
>
> Seems reasonable. I'll amend the proposal to commit to a first patch
> series in 2 weeks and to sending a new one every week or less (to
> avoid series getting massive). I'll also refrain from postponing
> responding to feedback and, when necessary, work in parallel between
> amending patches and working on new code. After all, I know how my
> schedule will be during the whole GSoC period, but I don't know how
> available those in the list will be to review it, so it's probably
> best to respond early.
>
>>> > (Note: due to a previous commitment, during a five-day period of July
>>> > I will only be able to work part-time on GSoC. The actual week will be
>>> > known over the next weeks.)
>>>
>>> Maybe you want to shift the schedule up to here by one week then?
>>> (e.g. the first period would be April 27  - May 23)
>>>
>
> I cannot shift the schedule one week earlier during the pre-code
> period because Google only releases mentor information on May 4, and
> the things I'm planning for the second period depend on the mentor.
> However, my classes only start in September 22, so I would have
> absolutely no problem continuing to work full-time on Git after the
> GSoC period is officially over to compensate for these five days.
>
>>> >
>>> > - July 28 - August 29
>>> > -- By the start of this period, send a patch with the builtin fully
>>> > implemented to the mailing list.
>>>
>>> /a patch/a patch series consisting of many patches/
>>> Experience shows that smaller patches are easier to review as
>>> it is more focused.
>
> I will reword it.
>
>>> Consider e.g. e86ab2c1cd (wt-status: convert to struct object_id,
>>> 2017-02-21) and the parents leading up to this commit. They work on the
>>> same big topic, but focus on very regional areas to ease review.
>>>
>>> > -- Fix bugs, test extensively, possibly extend test coverage for
>>> > git-add--interactive.
>>>
>>> AFAICT ('$ git grep "git add -i"') there is only t3701 testing the
>>> interactive add. Maybe we need to add tests first to document
>>> current behavior, before attempting a conversion?
>>
>> That should indeed be the first step, before doing much else.
>>
>> However, it does look as if t3701's 40 test cases provide fairly thorough
>> coverage.
>>
>>> This could go well into the period "May 4 - May 30", as writing
>>> tests would count as "Clarify implementation details".
>>
>> I agree with that, too.
>
> Seems reasonable. As I said above, working on patches (if possible)
> related to git-add--interactive will probably lead me to discovering
> coverage issues, which could then be dealt with in this pre-code
> period already with some guidance from my mentor.
>
>> Thanks for working on this!
>
> Thank *you*, and Stefan, for the careful review of it. It means a lot.
>
> -- Daniel.

^ permalink raw reply	[relevance 0%]

* Re: [GSoC] Proposal: turn git-add--interactive.perl into a builtin
  @ 2017-03-31  5:07  3%     ` Daniel Ferreira (theiostream)
  2017-03-31 19:06  0%       ` Daniel Ferreira (theiostream)
  0 siblings, 1 reply; 200+ results
From: Daniel Ferreira (theiostream) @ 2017-03-31  5:07 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Stefan Beller, Git Mailing List, Christian Couder

Hi Stefan & Johannes,

Thank you for the precious feedback on the proposal. I don't see much
sense in sending a full "v2" of it and have you read it all over
again, so I'll just answer to your comments directly.

Also, although the GSoC website allows me to send a "proposal draft"
to you through the website, since I've already sent it here that
shouldn't be necessary, correct? I intend to use it just to send the
final thing.

On Wed, Mar 29, 2017 at 9:01 PM, Johannes Schindelin
<Johannes.Schindelin@gmx.de> wrote:
> On Tue, 28 Mar 2017, Stefan Beller wrote:
>
>> On Sat, Mar 25, 2017 at 8:15 PM, Daniel Ferreira (theiostream)
>> <bnmvco@gmail.com> wrote:
>>
>> > SYNOPSIS
>> > There are many advantages to converting parts of git that are still
>> > scripts to C builtins, among which execution speed, improved
>> > compatibility and code deduplication.
>>
>> agreed.
>
> I would even add portability. But yeah, speed is a big thing. I am an
> extensive user of `git add -p` (which is backed by
> git-add--interactive.perl) and it is slow as molasses on Windows, just
> because it is a Perl script (and the Perl interpreter needs to emulate
> POSIX functionality that is frequently not even needed, such as: copying
> all memory and reopening all file descriptors in a fork() call only to
> exec() git.exe right away, tossing all of the diligently work into the
> dustbin).

Thanks for this example – it hadn't come to my mind since I don't use
Git on Windows. I'll be sure to complement the synopsis with it. :)

>
>> > FEASIBILITY
>> >
>> > There was only one discussion regarding the feasibility of its porting
>> > (https://public-inbox.org/git/CAP8UFD2PcBsU6=FK4OHVrB7E98ycohS_0pYcbCBar=of1HLx+Q@mail.gmail.com/).
>> > It resulted in a consensus that doing it would be a task too large –
>> > although interesting – for GSoC 2015 based on the amount of its lines
>> > of code. It is, however, only a few lines larger than
>> > git-rebase--interactive, which has been considered an appropriate
>> > idea. As such, it looks like a possible project for three months of
>> > full-time work.
>>
>> ok, it sounds a challenging project. (currently counting 1750 lines of
>> code). Scrolling over the source code, there are quite a couple of
>> functions, where the direct equivalent in C springs to mind.
>>
>> run_cmd_pipe -> see run-command.h
>> unquote_path -> unquote_c_style ?
>> refresh -> update_index_if_able()
>> list_modified -> iterate over "const struct cache_entry *ce = active_cache[i];"

Thank you for these functions. I don't think I will be able to specify
them in detail as part of the projected timeline (e.g. "June 1:
convert calls to refresh() to use update_index_if_able()") already
because there is not enough time prior to the proposal deadline to
study their behavior in detail, and I like to avoid talking about
things I don't fully understand. Although I think I can cite them as
examples for a thesis I had put elsewhere in the proposal that "Git
APIs in Perl already have functional equivalents in C".

Also, they will be great for my early investigation stage into
git-add--interactive. :) Once more, thanks for having listed them.

> Yes, I think it would be more important to acquaint oneself with the
> idiosynchracies of Git's internal "API" than to get familiar with Perl:
> interpreting what obscure Perl code does is something I would gladly do as
> a mentor.

That's really nice! I usually don't get stuck when trying to
understand code in languages I'm not too well acquainted with, but I
figured getting more familiar with Perl would speed development up.
But it does make sense that this "prior to May 4" might be better
invested learning about git's internals than Perl.

Question: do you suggest any pending bugfix to git-add--interactive or
to something related that might give some useful knowledge in advance?
(for the pre-code period). My microproject involves playing with the
dir_iterator interface, which is a great exercise in code refactoring
but really does not teach me too much about Git's architecture.

Even if you do not have an answer to this, I'm pretty sure I'll keep
this commitment to submitting some patch series somehow related to
git-add before GSoC begins, especially after this comment from
Johannes.

>
>> > PROJECTED TIMELINE
>> > - Prior to May 4
>> > -- Refine my basic knowledge of Perl
>> > -- Craft one or two small patches to some of Git's Perl components
>> > (preferentially to git-add--interactive itself) to improve my
>> > understanding of the language and of how Git's Perl scripts actually
>> > work

So yeah, I think this could be rewritten as:

- Prior to May 4
-- Craft two or three small patch series to git-add--interactive or
related components to improve my understanding of Git's internal
architecture, especially that related to git-add.

>
>> > - May 4 - May 30
>> > -- Clarify implementation details with my mentor, and work on a more
>> > detailed roadmap for the project
>> > -- Investigate roughly how to replace command invocations from the
>> > script with actual builtin functions; which Git APIs in Perl already
>> > have functional equivalents in C; which parts will require a full
>> > rewrite.
>> There are different approaches for replacing functionality in another
>> language. Examples:
>> * Implement the functionality in C and then have a "flag-day" commit
>>   783d7e865e (builtin-am: remove redirection to git-am.sh, 2015-08-04)
>>   This only works when the whole functionality was replaced in prior commits
>> * Implement partial functionality in C and call it via a helper function.
>>   3604242f08 (submodule: port init from shell to C, 2016-04-15)
>>   This works well for only partial conversions (the larger the thing to
>>   convert the more appealing this is, as it gets code shipped early.)
>>   When choosing this strategy, this part of the Project would be to
>>   identify parts that could be ported on its own without much
>>   additional glue-code.
>
> To offer my perspective: I strongly prefer the latter approach. Not only
> does it yield earlier results, it also makes it substantially easier to
> handle the project even if it should turn out to be a little larger than
> just 3 months.

I agree. I even think that the latter parts of this projected timeline
imply a choice for the second approach.

For now, Stefan's implementation in 3604242f08 (create a helper
builtin command, call it from a script, do it to other functions until
the whole script is replaced) seems the most natural way to do it. But
sadly, I still do not have enough knowledge about the project to be
able to specify in this proposal how (e.g. in what order) exactly I
intend to "divide" the code to do this. But I'm sure the answer to
this question will be clearer through contact with my mentor and with
growing experience in the project.

>
>> > - May 30 - June 30 (start of coding period)
>> > -- Define the architecture of the builtin within git (which
>> > functions/interfaces will it have? where will its code reside?).
>> > -- Implement a small subset of the builtin (to be defined with my
>> > mentor) and glue it into the existing Perl script. Present this as a
>> > first patch to get feedback early regarding the implementation and
>> > avoid piling up mistakes early.
>> > -- Do necessary changes based on this initial review.
>> > -- Have roughly 1/3 of the script's functionality ported to C.
>> >
>> > - June 30 - July 28
>> > -- Port the remainder of the script to a builtin.
>> > -- Have a weekly roadmap, sending a part of the patch every 15 days to
>> > the mailing list for review and to avoid massive commits by the end of
>> > GSoC.
>>
>> yeah; send early, send often. ;)
>
> Even better: push multiple times a day to a public repository, say, on
> GitHub. That allows for "Work In Progress" commits that not only serve as
> a backup but also as transparent report what was done.

Great idea. It can also be a good way to report my progress to my
mentor. (I'll do my best to avoid "[WIP]" commits with barely any
explanation).

As for the "timeline", I think it can be improved by some better
specification regarding the gradual process of the implementation
opposed to switching from the script to a builtin all at once.

>> > -- Apply suggestions from community reviews when possible; if not,
>> > save them for doing toward the end of GSoC (see below).
>>
>> Please do not underestimate the discussion by community, finding
>> consensus on list consumes a bit of time in some cases.
> I agree with this statement. Ideally, the first patch series would be
> ready to submit very soon into the project, something like 2 weeks (which
> is another point in favor of the helper approach outlined by Stefan).
> The smaller the patch series are, the more likely they will get in
> quickly. And the easier is it to address reviewers' comments, because you
> won't have to send out gazillion unchanged patches of a multi-dozen patch
> series just to address one typo in one patch.

Seems reasonable. I'll amend the proposal to commit to a first patch
series in 2 weeks and to sending a new one every week or less (to
avoid series getting massive). I'll also refrain from postponing
responding to feedback and, when necessary, work in parallel between
amending patches and working on new code. After all, I know how my
schedule will be during the whole GSoC period, but I don't know how
available those in the list will be to review it, so it's probably
best to respond early.

>> > (Note: due to a previous commitment, during a five-day period of July
>> > I will only be able to work part-time on GSoC. The actual week will be
>> > known over the next weeks.)
>>
>> Maybe you want to shift the schedule up to here by one week then?
>> (e.g. the first period would be April 27  - May 23)
>>

I cannot shift the schedule one week earlier during the pre-code
period because Google only releases mentor information on May 4, and
the things I'm planning for the second period depend on the mentor.
However, my classes only start in September 22, so I would have
absolutely no problem continuing to work full-time on Git after the
GSoC period is officially over to compensate for these five days.

>> >
>> > - July 28 - August 29
>> > -- By the start of this period, send a patch with the builtin fully
>> > implemented to the mailing list.
>>
>> /a patch/a patch series consisting of many patches/
>> Experience shows that smaller patches are easier to review as
>> it is more focused.

I will reword it.

>> Consider e.g. e86ab2c1cd (wt-status: convert to struct object_id,
>> 2017-02-21) and the parents leading up to this commit. They work on the
>> same big topic, but focus on very regional areas to ease review.
>>
>> > -- Fix bugs, test extensively, possibly extend test coverage for
>> > git-add--interactive.
>>
>> AFAICT ('$ git grep "git add -i"') there is only t3701 testing the
>> interactive add. Maybe we need to add tests first to document
>> current behavior, before attempting a conversion?
>
> That should indeed be the first step, before doing much else.
>
> However, it does look as if t3701's 40 test cases provide fairly thorough
> coverage.
>
>> This could go well into the period "May 4 - May 30", as writing
>> tests would count as "Clarify implementation details".
>
> I agree with that, too.

Seems reasonable. As I said above, working on patches (if possible)
related to git-add--interactive will probably lead me to discovering
coverage issues, which could then be dealt with in this pre-code
period already with some guidance from my mentor.

> Thanks for working on this!

Thank *you*, and Stefan, for the careful review of it. It means a lot.

-- Daniel.

^ permalink raw reply	[relevance 3%]

* [PATCH v3 13/20] builtin/pull: convert to struct object_id
  @ 2017-03-31  1:39  3% ` brian m. carlson
  0 siblings, 0 replies; 200+ results
From: brian m. carlson @ 2017-03-31  1:39 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Nguyễn Thái Ngọc Duy, Junio C Hamano

Convert virtually all uses of unsigned char [20] to struct object_id.
Leave all the arguments that come from struct sha1_array, as these will
be converted in a later patch.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/pull.c | 72 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index a9f7553f30..704ce1f042 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -515,7 +515,7 @@ static int run_fetch(const char *repo, const char **refspecs)
  * "Pulls into void" by branching off merge_head.
  */
 static int pull_into_void(const unsigned char *merge_head,
-		const unsigned char *curr_head)
+		const struct object_id *curr_head)
 {
 	/*
 	 * Two-way merge: we treat the index as based on an empty tree,
@@ -526,7 +526,7 @@ static int pull_into_void(const unsigned char *merge_head,
 	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
 		return 1;
 
-	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+	if (update_ref("initial pull", "HEAD", merge_head, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
 		return 1;
 
 	return 0;
@@ -647,7 +647,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
  * current branch forked from its remote tracking branch. Returns 0 on success,
  * -1 on failure.
  */
-static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
+static int get_rebase_fork_point(struct object_id *fork_point, const char *repo,
 		const char *refspec)
 {
 	int ret;
@@ -678,7 +678,7 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
 	if (ret)
 		goto cleanup;
 
-	ret = get_sha1_hex(sb.buf, fork_point);
+	ret = get_oid_hex(sb.buf, fork_point);
 	if (ret)
 		goto cleanup;
 
@@ -691,24 +691,24 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
  * Sets merge_base to the octopus merge base of curr_head, merge_head and
  * fork_point. Returns 0 if a merge base is found, 1 otherwise.
  */
-static int get_octopus_merge_base(unsigned char *merge_base,
-		const unsigned char *curr_head,
+static int get_octopus_merge_base(struct object_id *merge_base,
+		const struct object_id *curr_head,
 		const unsigned char *merge_head,
-		const unsigned char *fork_point)
+		const struct object_id *fork_point)
 {
 	struct commit_list *revs = NULL, *result;
 
-	commit_list_insert(lookup_commit_reference(curr_head), &revs);
+	commit_list_insert(lookup_commit_reference(curr_head->hash), &revs);
 	commit_list_insert(lookup_commit_reference(merge_head), &revs);
-	if (!is_null_sha1(fork_point))
-		commit_list_insert(lookup_commit_reference(fork_point), &revs);
+	if (!is_null_oid(fork_point))
+		commit_list_insert(lookup_commit_reference(fork_point->hash), &revs);
 
 	result = reduce_heads(get_octopus_merge_bases(revs));
 	free_commit_list(revs);
 	if (!result)
 		return 1;
 
-	hashcpy(merge_base, result->item->object.oid.hash);
+	oidcpy(merge_base, &result->item->object.oid);
 	return 0;
 }
 
@@ -717,16 +717,16 @@ static int get_octopus_merge_base(unsigned char *merge_base,
  * fork point calculated by get_rebase_fork_point(), runs git-rebase with the
  * appropriate arguments and returns its exit status.
  */
-static int run_rebase(const unsigned char *curr_head,
+static int run_rebase(const struct object_id *curr_head,
 		const unsigned char *merge_head,
-		const unsigned char *fork_point)
+		const struct object_id *fork_point)
 {
 	int ret;
-	unsigned char oct_merge_base[GIT_SHA1_RAWSZ];
+	struct object_id oct_merge_base;
 	struct argv_array args = ARGV_ARRAY_INIT;
 
-	if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point))
-		if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point))
+	if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
+		if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point))
 			fork_point = NULL;
 
 	argv_array_push(&args, "rebase");
@@ -756,8 +756,8 @@ static int run_rebase(const unsigned char *curr_head,
 	argv_array_push(&args, "--onto");
 	argv_array_push(&args, sha1_to_hex(merge_head));
 
-	if (fork_point && !is_null_sha1(fork_point))
-		argv_array_push(&args, sha1_to_hex(fork_point));
+	if (fork_point && !is_null_oid(fork_point))
+		argv_array_push(&args, oid_to_hex(fork_point));
 	else
 		argv_array_push(&args, sha1_to_hex(merge_head));
 
@@ -770,8 +770,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 {
 	const char *repo, **refspecs;
 	struct sha1_array merge_heads = SHA1_ARRAY_INIT;
-	unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
-	unsigned char rebase_fork_point[GIT_SHA1_RAWSZ];
+	struct object_id orig_head, curr_head;
+	struct object_id rebase_fork_point;
 
 	if (!getenv("GIT_REFLOG_ACTION"))
 		set_reflog_message(argc, argv);
@@ -794,8 +794,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (file_exists(git_path("MERGE_HEAD")))
 		die_conclude_merge();
 
-	if (get_sha1("HEAD", orig_head))
-		hashclr(orig_head);
+	if (get_oid("HEAD", &orig_head))
+		oidclr(&orig_head);
 
 	if (!opt_rebase && opt_autostash != -1)
 		die(_("--[no-]autostash option is only valid with --rebase."));
@@ -805,15 +805,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		if (opt_autostash != -1)
 			autostash = opt_autostash;
 
-		if (is_null_sha1(orig_head) && !is_cache_unborn())
+		if (is_null_oid(&orig_head) && !is_cache_unborn())
 			die(_("Updating an unborn branch with changes added to the index."));
 
 		if (!autostash)
 			require_clean_work_tree(N_("pull with rebase"),
 				_("please commit or stash them."), 1, 0);
 
-		if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
-			hashclr(rebase_fork_point);
+		if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
+			oidclr(&rebase_fork_point);
 	}
 
 	if (run_fetch(repo, refspecs))
@@ -822,11 +822,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (opt_dry_run)
 		return 0;
 
-	if (get_sha1("HEAD", curr_head))
-		hashclr(curr_head);
+	if (get_oid("HEAD", &curr_head))
+		oidclr(&curr_head);
 
-	if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) &&
-			hashcmp(orig_head, curr_head)) {
+	if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
+			oidcmp(&orig_head, &curr_head)) {
 		/*
 		 * The fetch involved updating the current branch.
 		 *
@@ -837,15 +837,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 		warning(_("fetch updated the current branch head.\n"
 			"fast-forwarding your working tree from\n"
-			"commit %s."), sha1_to_hex(orig_head));
+			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(orig_head, curr_head, 0))
+		if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
 				"output, run\n"
 				"$ git reset --hard\n"
-				"to recover."), sha1_to_hex(orig_head));
+				"to recover."), oid_to_hex(&orig_head));
 	}
 
 	get_merge_heads(&merge_heads);
@@ -853,10 +853,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (!merge_heads.nr)
 		die_no_merge_candidates(repo, refspecs);
 
-	if (is_null_sha1(orig_head)) {
+	if (is_null_oid(&orig_head)) {
 		if (merge_heads.nr > 1)
 			die(_("Cannot merge multiple branches into empty head."));
-		return pull_into_void(*merge_heads.sha1, curr_head);
+		return pull_into_void(*merge_heads.sha1, &curr_head);
 	}
 	if (opt_rebase && merge_heads.nr > 1)
 		die(_("Cannot rebase onto multiple branches."));
@@ -865,7 +865,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		struct commit_list *list = NULL;
 		struct commit *merge_head, *head;
 
-		head = lookup_commit_reference(orig_head);
+		head = lookup_commit_reference(orig_head.hash);
 		commit_list_insert(head, &list);
 		merge_head = lookup_commit_reference(merge_heads.sha1[0]);
 		if (is_descendant_of(merge_head, list)) {
@@ -873,7 +873,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			opt_ff = "--ff-only";
 			return run_merge();
 		}
-		return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
+		return run_rebase(&curr_head, *merge_heads.sha1, &rebase_fork_point);
 	} else {
 		return run_merge();
 	}

^ permalink raw reply related	[relevance 3%]

* [PATCH v2 14/21] builtin/pull: convert to struct object_id
  @ 2017-03-26 16:01  3% ` brian m. carlson
  0 siblings, 0 replies; 200+ results
From: brian m. carlson @ 2017-03-26 16:01 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Nguyễn Thái Ngọc Duy, Junio C Hamano

Convert virtually all uses of unsigned char [20] to struct object_id.
Leave all the arguments that come from struct sha1_array, as these will
be converted in a later patch.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/pull.c | 72 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index a9f7553f30..704ce1f042 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -515,7 +515,7 @@ static int run_fetch(const char *repo, const char **refspecs)
  * "Pulls into void" by branching off merge_head.
  */
 static int pull_into_void(const unsigned char *merge_head,
-		const unsigned char *curr_head)
+		const struct object_id *curr_head)
 {
 	/*
 	 * Two-way merge: we treat the index as based on an empty tree,
@@ -526,7 +526,7 @@ static int pull_into_void(const unsigned char *merge_head,
 	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
 		return 1;
 
-	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+	if (update_ref("initial pull", "HEAD", merge_head, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
 		return 1;
 
 	return 0;
@@ -647,7 +647,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
  * current branch forked from its remote tracking branch. Returns 0 on success,
  * -1 on failure.
  */
-static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
+static int get_rebase_fork_point(struct object_id *fork_point, const char *repo,
 		const char *refspec)
 {
 	int ret;
@@ -678,7 +678,7 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
 	if (ret)
 		goto cleanup;
 
-	ret = get_sha1_hex(sb.buf, fork_point);
+	ret = get_oid_hex(sb.buf, fork_point);
 	if (ret)
 		goto cleanup;
 
@@ -691,24 +691,24 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
  * Sets merge_base to the octopus merge base of curr_head, merge_head and
  * fork_point. Returns 0 if a merge base is found, 1 otherwise.
  */
-static int get_octopus_merge_base(unsigned char *merge_base,
-		const unsigned char *curr_head,
+static int get_octopus_merge_base(struct object_id *merge_base,
+		const struct object_id *curr_head,
 		const unsigned char *merge_head,
-		const unsigned char *fork_point)
+		const struct object_id *fork_point)
 {
 	struct commit_list *revs = NULL, *result;
 
-	commit_list_insert(lookup_commit_reference(curr_head), &revs);
+	commit_list_insert(lookup_commit_reference(curr_head->hash), &revs);
 	commit_list_insert(lookup_commit_reference(merge_head), &revs);
-	if (!is_null_sha1(fork_point))
-		commit_list_insert(lookup_commit_reference(fork_point), &revs);
+	if (!is_null_oid(fork_point))
+		commit_list_insert(lookup_commit_reference(fork_point->hash), &revs);
 
 	result = reduce_heads(get_octopus_merge_bases(revs));
 	free_commit_list(revs);
 	if (!result)
 		return 1;
 
-	hashcpy(merge_base, result->item->object.oid.hash);
+	oidcpy(merge_base, &result->item->object.oid);
 	return 0;
 }
 
@@ -717,16 +717,16 @@ static int get_octopus_merge_base(unsigned char *merge_base,
  * fork point calculated by get_rebase_fork_point(), runs git-rebase with the
  * appropriate arguments and returns its exit status.
  */
-static int run_rebase(const unsigned char *curr_head,
+static int run_rebase(const struct object_id *curr_head,
 		const unsigned char *merge_head,
-		const unsigned char *fork_point)
+		const struct object_id *fork_point)
 {
 	int ret;
-	unsigned char oct_merge_base[GIT_SHA1_RAWSZ];
+	struct object_id oct_merge_base;
 	struct argv_array args = ARGV_ARRAY_INIT;
 
-	if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point))
-		if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point))
+	if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
+		if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point))
 			fork_point = NULL;
 
 	argv_array_push(&args, "rebase");
@@ -756,8 +756,8 @@ static int run_rebase(const unsigned char *curr_head,
 	argv_array_push(&args, "--onto");
 	argv_array_push(&args, sha1_to_hex(merge_head));
 
-	if (fork_point && !is_null_sha1(fork_point))
-		argv_array_push(&args, sha1_to_hex(fork_point));
+	if (fork_point && !is_null_oid(fork_point))
+		argv_array_push(&args, oid_to_hex(fork_point));
 	else
 		argv_array_push(&args, sha1_to_hex(merge_head));
 
@@ -770,8 +770,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 {
 	const char *repo, **refspecs;
 	struct sha1_array merge_heads = SHA1_ARRAY_INIT;
-	unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
-	unsigned char rebase_fork_point[GIT_SHA1_RAWSZ];
+	struct object_id orig_head, curr_head;
+	struct object_id rebase_fork_point;
 
 	if (!getenv("GIT_REFLOG_ACTION"))
 		set_reflog_message(argc, argv);
@@ -794,8 +794,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (file_exists(git_path("MERGE_HEAD")))
 		die_conclude_merge();
 
-	if (get_sha1("HEAD", orig_head))
-		hashclr(orig_head);
+	if (get_oid("HEAD", &orig_head))
+		oidclr(&orig_head);
 
 	if (!opt_rebase && opt_autostash != -1)
 		die(_("--[no-]autostash option is only valid with --rebase."));
@@ -805,15 +805,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		if (opt_autostash != -1)
 			autostash = opt_autostash;
 
-		if (is_null_sha1(orig_head) && !is_cache_unborn())
+		if (is_null_oid(&orig_head) && !is_cache_unborn())
 			die(_("Updating an unborn branch with changes added to the index."));
 
 		if (!autostash)
 			require_clean_work_tree(N_("pull with rebase"),
 				_("please commit or stash them."), 1, 0);
 
-		if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
-			hashclr(rebase_fork_point);
+		if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
+			oidclr(&rebase_fork_point);
 	}
 
 	if (run_fetch(repo, refspecs))
@@ -822,11 +822,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (opt_dry_run)
 		return 0;
 
-	if (get_sha1("HEAD", curr_head))
-		hashclr(curr_head);
+	if (get_oid("HEAD", &curr_head))
+		oidclr(&curr_head);
 
-	if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) &&
-			hashcmp(orig_head, curr_head)) {
+	if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
+			oidcmp(&orig_head, &curr_head)) {
 		/*
 		 * The fetch involved updating the current branch.
 		 *
@@ -837,15 +837,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 		warning(_("fetch updated the current branch head.\n"
 			"fast-forwarding your working tree from\n"
-			"commit %s."), sha1_to_hex(orig_head));
+			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(orig_head, curr_head, 0))
+		if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
 				"output, run\n"
 				"$ git reset --hard\n"
-				"to recover."), sha1_to_hex(orig_head));
+				"to recover."), oid_to_hex(&orig_head));
 	}
 
 	get_merge_heads(&merge_heads);
@@ -853,10 +853,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (!merge_heads.nr)
 		die_no_merge_candidates(repo, refspecs);
 
-	if (is_null_sha1(orig_head)) {
+	if (is_null_oid(&orig_head)) {
 		if (merge_heads.nr > 1)
 			die(_("Cannot merge multiple branches into empty head."));
-		return pull_into_void(*merge_heads.sha1, curr_head);
+		return pull_into_void(*merge_heads.sha1, &curr_head);
 	}
 	if (opt_rebase && merge_heads.nr > 1)
 		die(_("Cannot rebase onto multiple branches."));
@@ -865,7 +865,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		struct commit_list *list = NULL;
 		struct commit *merge_head, *head;
 
-		head = lookup_commit_reference(orig_head);
+		head = lookup_commit_reference(orig_head.hash);
 		commit_list_insert(head, &list);
 		merge_head = lookup_commit_reference(merge_heads.sha1[0]);
 		if (is_descendant_of(merge_head, list)) {
@@ -873,7 +873,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			opt_ff = "--ff-only";
 			return run_merge();
 		}
-		return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
+		return run_rebase(&curr_head, *merge_heads.sha1, &rebase_fork_point);
 	} else {
 		return run_merge();
 	}

^ permalink raw reply related	[relevance 3%]

* [PATCH 13/20] builtin/pull: convert to struct object_id
  @ 2017-03-18 21:19  3% ` brian m. carlson
  0 siblings, 0 replies; 200+ results
From: brian m. carlson @ 2017-03-18 21:19 UTC (permalink / raw)
  To: git; +Cc: Jeff King, Nguyễn Thái Ngọc Duy

Convert virtually all uses of unsigned char [20] to struct object_id.
Leave all the arguments that come from struct sha1_array, as these will
be converted in a later patch.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/pull.c | 72 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index a9f7553f30..704ce1f042 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -515,7 +515,7 @@ static int run_fetch(const char *repo, const char **refspecs)
  * "Pulls into void" by branching off merge_head.
  */
 static int pull_into_void(const unsigned char *merge_head,
-		const unsigned char *curr_head)
+		const struct object_id *curr_head)
 {
 	/*
 	 * Two-way merge: we treat the index as based on an empty tree,
@@ -526,7 +526,7 @@ static int pull_into_void(const unsigned char *merge_head,
 	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
 		return 1;
 
-	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+	if (update_ref("initial pull", "HEAD", merge_head, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
 		return 1;
 
 	return 0;
@@ -647,7 +647,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
  * current branch forked from its remote tracking branch. Returns 0 on success,
  * -1 on failure.
  */
-static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
+static int get_rebase_fork_point(struct object_id *fork_point, const char *repo,
 		const char *refspec)
 {
 	int ret;
@@ -678,7 +678,7 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
 	if (ret)
 		goto cleanup;
 
-	ret = get_sha1_hex(sb.buf, fork_point);
+	ret = get_oid_hex(sb.buf, fork_point);
 	if (ret)
 		goto cleanup;
 
@@ -691,24 +691,24 @@ static int get_rebase_fork_point(unsigned char *fork_point, const char *repo,
  * Sets merge_base to the octopus merge base of curr_head, merge_head and
  * fork_point. Returns 0 if a merge base is found, 1 otherwise.
  */
-static int get_octopus_merge_base(unsigned char *merge_base,
-		const unsigned char *curr_head,
+static int get_octopus_merge_base(struct object_id *merge_base,
+		const struct object_id *curr_head,
 		const unsigned char *merge_head,
-		const unsigned char *fork_point)
+		const struct object_id *fork_point)
 {
 	struct commit_list *revs = NULL, *result;
 
-	commit_list_insert(lookup_commit_reference(curr_head), &revs);
+	commit_list_insert(lookup_commit_reference(curr_head->hash), &revs);
 	commit_list_insert(lookup_commit_reference(merge_head), &revs);
-	if (!is_null_sha1(fork_point))
-		commit_list_insert(lookup_commit_reference(fork_point), &revs);
+	if (!is_null_oid(fork_point))
+		commit_list_insert(lookup_commit_reference(fork_point->hash), &revs);
 
 	result = reduce_heads(get_octopus_merge_bases(revs));
 	free_commit_list(revs);
 	if (!result)
 		return 1;
 
-	hashcpy(merge_base, result->item->object.oid.hash);
+	oidcpy(merge_base, &result->item->object.oid);
 	return 0;
 }
 
@@ -717,16 +717,16 @@ static int get_octopus_merge_base(unsigned char *merge_base,
  * fork point calculated by get_rebase_fork_point(), runs git-rebase with the
  * appropriate arguments and returns its exit status.
  */
-static int run_rebase(const unsigned char *curr_head,
+static int run_rebase(const struct object_id *curr_head,
 		const unsigned char *merge_head,
-		const unsigned char *fork_point)
+		const struct object_id *fork_point)
 {
 	int ret;
-	unsigned char oct_merge_base[GIT_SHA1_RAWSZ];
+	struct object_id oct_merge_base;
 	struct argv_array args = ARGV_ARRAY_INIT;
 
-	if (!get_octopus_merge_base(oct_merge_base, curr_head, merge_head, fork_point))
-		if (!is_null_sha1(fork_point) && !hashcmp(oct_merge_base, fork_point))
+	if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
+		if (!is_null_oid(fork_point) && !oidcmp(&oct_merge_base, fork_point))
 			fork_point = NULL;
 
 	argv_array_push(&args, "rebase");
@@ -756,8 +756,8 @@ static int run_rebase(const unsigned char *curr_head,
 	argv_array_push(&args, "--onto");
 	argv_array_push(&args, sha1_to_hex(merge_head));
 
-	if (fork_point && !is_null_sha1(fork_point))
-		argv_array_push(&args, sha1_to_hex(fork_point));
+	if (fork_point && !is_null_oid(fork_point))
+		argv_array_push(&args, oid_to_hex(fork_point));
 	else
 		argv_array_push(&args, sha1_to_hex(merge_head));
 
@@ -770,8 +770,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 {
 	const char *repo, **refspecs;
 	struct sha1_array merge_heads = SHA1_ARRAY_INIT;
-	unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
-	unsigned char rebase_fork_point[GIT_SHA1_RAWSZ];
+	struct object_id orig_head, curr_head;
+	struct object_id rebase_fork_point;
 
 	if (!getenv("GIT_REFLOG_ACTION"))
 		set_reflog_message(argc, argv);
@@ -794,8 +794,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (file_exists(git_path("MERGE_HEAD")))
 		die_conclude_merge();
 
-	if (get_sha1("HEAD", orig_head))
-		hashclr(orig_head);
+	if (get_oid("HEAD", &orig_head))
+		oidclr(&orig_head);
 
 	if (!opt_rebase && opt_autostash != -1)
 		die(_("--[no-]autostash option is only valid with --rebase."));
@@ -805,15 +805,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		if (opt_autostash != -1)
 			autostash = opt_autostash;
 
-		if (is_null_sha1(orig_head) && !is_cache_unborn())
+		if (is_null_oid(&orig_head) && !is_cache_unborn())
 			die(_("Updating an unborn branch with changes added to the index."));
 
 		if (!autostash)
 			require_clean_work_tree(N_("pull with rebase"),
 				_("please commit or stash them."), 1, 0);
 
-		if (get_rebase_fork_point(rebase_fork_point, repo, *refspecs))
-			hashclr(rebase_fork_point);
+		if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
+			oidclr(&rebase_fork_point);
 	}
 
 	if (run_fetch(repo, refspecs))
@@ -822,11 +822,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (opt_dry_run)
 		return 0;
 
-	if (get_sha1("HEAD", curr_head))
-		hashclr(curr_head);
+	if (get_oid("HEAD", &curr_head))
+		oidclr(&curr_head);
 
-	if (!is_null_sha1(orig_head) && !is_null_sha1(curr_head) &&
-			hashcmp(orig_head, curr_head)) {
+	if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
+			oidcmp(&orig_head, &curr_head)) {
 		/*
 		 * The fetch involved updating the current branch.
 		 *
@@ -837,15 +837,15 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 		warning(_("fetch updated the current branch head.\n"
 			"fast-forwarding your working tree from\n"
-			"commit %s."), sha1_to_hex(orig_head));
+			"commit %s."), oid_to_hex(&orig_head));
 
-		if (checkout_fast_forward(orig_head, curr_head, 0))
+		if (checkout_fast_forward(orig_head.hash, curr_head.hash, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
 				"output, run\n"
 				"$ git reset --hard\n"
-				"to recover."), sha1_to_hex(orig_head));
+				"to recover."), oid_to_hex(&orig_head));
 	}
 
 	get_merge_heads(&merge_heads);
@@ -853,10 +853,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (!merge_heads.nr)
 		die_no_merge_candidates(repo, refspecs);
 
-	if (is_null_sha1(orig_head)) {
+	if (is_null_oid(&orig_head)) {
 		if (merge_heads.nr > 1)
 			die(_("Cannot merge multiple branches into empty head."));
-		return pull_into_void(*merge_heads.sha1, curr_head);
+		return pull_into_void(*merge_heads.sha1, &curr_head);
 	}
 	if (opt_rebase && merge_heads.nr > 1)
 		die(_("Cannot rebase onto multiple branches."));
@@ -865,7 +865,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		struct commit_list *list = NULL;
 		struct commit *merge_head, *head;
 
-		head = lookup_commit_reference(orig_head);
+		head = lookup_commit_reference(orig_head.hash);
 		commit_list_insert(head, &list);
 		merge_head = lookup_commit_reference(merge_heads.sha1[0]);
 		if (is_descendant_of(merge_head, list)) {
@@ -873,7 +873,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			opt_ff = "--ff-only";
 			return run_merge();
 		}
-		return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
+		return run_rebase(&curr_head, *merge_heads.sha1, &rebase_fork_point);
 	} else {
 		return run_merge();
 	}

^ permalink raw reply related	[relevance 3%]

* Re: Bug with .gitignore and branch switching
  2017-03-17 21:23  6% ` Junio C Hamano
  2017-03-17 21:58  0%   ` Stefan Beller
  2017-03-17 22:02  0%   ` Jonathan Nieder
@ 2017-03-18  4:30  3%   ` Nevada Sanchez
  2 siblings, 0 replies; 200+ results
From: Nevada Sanchez @ 2017-03-18  4:30 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Fri, Mar 17, 2017 at 5:23 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Nevada Sanchez <sanchez.nevada@gmail.com> writes:
>
>> Here's an easy to reproduce bug. It's the only example I know of where
>> git legitimately loses data in a way that is unrecoverable,
>> unexpected, and without warning.
>
> This is an example of a user explicitly telling git to discard data
> and git performing as it is told.
>
> There is no "untracked but precious" vs "untracked and expendable"
> difference in the current system.  An untracked file that matches
> patterns listed in .gitignore is treated as the latter.
>
> When you have an untracked file that .gitignore knows about in the
> working tree while you are on "feature", if switching to another
> branch requires to remove that file, the content there is deemed
> expendable, because the user said so by listing it in .gitignore.
>
> We've discussed the lack of "untracked but precious" class a few
> times on the list in the past, but I do not recall the topic came up
> in the recent past.  It perhaps is because nobody found that class
> useful enough so far.

I must admit that I missed that attribute of .gitignore (i.e.
untracked and **expendable**). I have grown accustomed to Git being
rather conservative and erring on the side of not losing data unless
the user is doing something deliberate (for example, 'git clean' won't
work unless you force it, checkouts fail if they do anything that
might lose data... unless it is in .gitignore, as I just learned).
When I saw this behavior, I assumed that it was a bug.

This isn't necessarily a situation I need to have fixed--it is not
part of my workflow and since that fateful commit, all feature
branches checked out after the change to .gitignore will not have any
problems as I switch branches. It was an unfortunate surprise to one
of my co-workers, not long after I reassured him that git was
conservative and will almost never accidentally lose data (even if it
means going to 'git reflog').

In keeping with this spirit, I would tend to lean towards having
"untracked but precious" being the default behavior (more
conservative), and if a user wants "untracked but expendable"
behavior, then that case requires special effort from the user (like
learning about and using a new type of ignore file). My guess is that
if the user is both ignoring and committing something to their
repository, it is probably a mistake, and as that user, I would rather
discover that mistake early with loud warning messages (and/or a
suggestion to use an alternate ignore strategy, or config flag), than
learn about it by losing data.

In summary, I do not need this fixed for my workflow, but want to
bring it to light in case other users are being similarly surprised. I
struggle to guess how far reaching of an impact it would have on
existing users to change the default behavior, but it would probably
be less than that of the push default behavior change that happened
not too long ago.

A quick and easy immediate step is to make note of this behavior in
the very first sentence of gitignore(5):

> A gitignore file specifies intentionally untracked files that Git should ignore *and that Git is allowed to overwrite without warning*.

More details about untracked but expendable can be placed in the NOTES
section, but the last part of that sentence would be quite helpful.

Thank you,
-Nevada

^ permalink raw reply	[relevance 3%]

* Re: Bug with .gitignore and branch switching
  2017-03-17 22:02  0%   ` Jonathan Nieder
  2017-03-17 22:36  4%     ` Junio C Hamano
@ 2017-03-18  3:40  6%     ` Duy Nguyen
  1 sibling, 0 replies; 200+ results
From: Duy Nguyen @ 2017-03-18  3:40 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Junio C Hamano, Nevada Sanchez, Git Mailing List

On Sat, Mar 18, 2017 at 5:02 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:
> Junio C Hamano wrote:
>
>> There is no "untracked but precious" vs "untracked and expendable"
>> difference in the current system.  An untracked file that matches
>> patterns listed in .gitignore is treated as the latter.
> [...]
>> We've discussed the lack of "untracked but precious" class a few
>> times on the list in the past, but I do not recall the topic came up
>> in the recent past.  It perhaps is because nobody found that class
>> useful enough so far.
>
> The most recent example I can find is 2010:
> http://public-inbox.org/git/4C6A1C5B.4030304@workspacewhiz.com/.
>
> It also came up in 2007:
> http://public-inbox.org/git/C0E9F681E68D48EB8989022D11FEE3D1@ntdev.corp.microsoft.com/
> Earlier in that year it even made the "What's not in 1.5.2" list.
> http://public-inbox.org/git/11793556383977-git-send-email-junkio@cox.net/
>
> Perhaps those references could be a useful starting point for an
> interested person's thinking.

I think I made it work in 2014 [1] using new "precious" attribute, but
never submitted it, probably because I was worried about the
interaction with untracked cache (adding .gitattributes as a new
dependency) though maybe we can avoid that by always checking for
preciousness after all the tree walking/filtering is done, either with
or without untracked cache. But I never addressed that loose end. Then
again, it could also be another useful starting point for interested
person's thinking ;-)

[1] https://github.com/pclouds/git/commit/0e7f7afa1879b055369ebd3f1224311c43c8a32b
-- 
Duy

^ permalink raw reply	[relevance 6%]

* Re: Bug with .gitignore and branch switching
  2017-03-17 22:02  0%   ` Jonathan Nieder
@ 2017-03-17 22:36  4%     ` Junio C Hamano
  2017-03-18  3:40  6%     ` Duy Nguyen
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2017-03-17 22:36 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Nevada Sanchez, git

Jonathan Nieder <jrnieder@gmail.com> writes:

> The most recent example I can find is 2010:
> http://public-inbox.org/git/4C6A1C5B.4030304@workspacewhiz.com/.
>
> It also came up in 2007:
> http://public-inbox.org/git/C0E9F681E68D48EB8989022D11FEE3D1@ntdev.corp.microsoft.com/
> Earlier in that year it even made the "What's not in 1.5.2" list.
> http://public-inbox.org/git/11793556383977-git-send-email-junkio@cox.net/
>
> Perhaps those references could be a useful starting point for an
> interested person's thinking.

Thanks for links.  It seems that my thinking back in 1.5.3 timeperiod
was to introduce "precious" attribute.

I noticed that among the four-message "What's not in 1.5.2" series,
3/4 has a large discussion that may be relevant to Brandon's
"submodule is-active" thing.

^ permalink raw reply	[relevance 4%]

* Re: Bug with .gitignore and branch switching
  2017-03-17 21:23  6% ` Junio C Hamano
@ 2017-03-17 21:58  0%   ` Stefan Beller
  2017-03-17 22:02  0%   ` Jonathan Nieder
  2017-03-18  4:30  3%   ` Nevada Sanchez
  2 siblings, 0 replies; 200+ results
From: Stefan Beller @ 2017-03-17 21:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Nevada Sanchez, git@vger.kernel.org

On Fri, Mar 17, 2017 at 2:23 PM, Junio C Hamano <gitster@pobox.com> wrote:
> We've discussed the lack of "untracked but precious" class a few
> times on the list in the past, but I do not recall the topic came up
> in the recent past.  It perhaps is because nobody found that class
> useful enough so far.

My gut reaction on reading the bug report was that the root cause is
git-checkout doing the wrong thing by default. (cf. Git-Merge-2017,
"What’s Wrong With Git?", I am not sure if the video is yet available)

One argument in that talk was that Git promises to do "work on multiple
branches in parallel (context-switched, single threaded)", and git-checkout
is the apparent command to switch to another context (branch).
However by putting away only tracked content, we miss
doing a proper context switch for untracked and ignored files.

That partial switch has advantages in the typical use case, e.g.
* compiled objects in the worktree may not need to be recompiled.
* no need to do work for the untracked files (e.g. move to a special
  location).

Both these reasons argue for performance, instead of "correctness"
in the sense of "easy-to-understand commands for top level principles".

And in that talk the presenter concluded that git-stash was only invented
to circumvent these "correctness" problems, such that if git-checkout
were to also (de)populate the untracked and ignored files on branch
switch we would not need git-stash, because git-checkout did it for you
already. And by the omission of git-stash and an apparent
easier-to-understand git-checkout the whole git suite would become
easier for users.

I further conclude that when git-checkout were to behave "correct" as
outlined above, then this class of bug reports would not occur.

Just food for thought.

Thanks,
Stefan

^ permalink raw reply	[relevance 0%]

* Re: Bug with .gitignore and branch switching
  2017-03-17 21:23  6% ` Junio C Hamano
  2017-03-17 21:58  0%   ` Stefan Beller
@ 2017-03-17 22:02  0%   ` Jonathan Nieder
  2017-03-17 22:36  4%     ` Junio C Hamano
  2017-03-18  3:40  6%     ` Duy Nguyen
  2017-03-18  4:30  3%   ` Nevada Sanchez
  2 siblings, 2 replies; 200+ results
From: Jonathan Nieder @ 2017-03-17 22:02 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Nevada Sanchez, git

Junio C Hamano wrote:

> There is no "untracked but precious" vs "untracked and expendable"
> difference in the current system.  An untracked file that matches
> patterns listed in .gitignore is treated as the latter.
[...]
> We've discussed the lack of "untracked but precious" class a few
> times on the list in the past, but I do not recall the topic came up
> in the recent past.  It perhaps is because nobody found that class
> useful enough so far.

The most recent example I can find is 2010:
http://public-inbox.org/git/4C6A1C5B.4030304@workspacewhiz.com/.

It also came up in 2007:
http://public-inbox.org/git/C0E9F681E68D48EB8989022D11FEE3D1@ntdev.corp.microsoft.com/
Earlier in that year it even made the "What's not in 1.5.2" list.
http://public-inbox.org/git/11793556383977-git-send-email-junkio@cox.net/

Perhaps those references could be a useful starting point for an
interested person's thinking.

Jonathan

^ permalink raw reply	[relevance 0%]

* Re: Bug with .gitignore and branch switching
    2017-03-17 21:23  6% ` Junio C Hamano
@ 2017-03-17 21:54  5% ` Jonathan Nieder
  1 sibling, 0 replies; 200+ results
From: Jonathan Nieder @ 2017-03-17 21:54 UTC (permalink / raw)
  To: Nevada Sanchez; +Cc: git

Hi Nevada,

Nevada Sanchez wrote:

> # Commit a file that will end up in .gitignore
> echo 'original settings' > mine.conf
> git add mine.conf
> git commit -m "Unknowingly committed my settings."
>
> echo '*.conf' > .gitignore
> git add .gitignore
> git commit -m "Users shouldn't commit their settings"

Naming a file in .gitignore tells git that you do not want to track it
and are giving git permission to write over it.  This commonly happens
when people check in build products.  For example:

	git rm -f my-build-product
	echo /my-build-product >>.gitignore
	git commit -m "Remove generated my-build-product file"
	make my-build-product

	git checkout HEAD^

Without that rule, this 'git checkout' command would fail.

That said, there are some cases (e.g. the .conf file case you mention)
where a person would want git not to track a file but do not want to
give git permission to write over it.  As you've seen, .gitignore does
not work well for this. :/

Ideas for next steps:

 1. The gitignore(5) manpage does not do a good job of emphasizing
    that files named there are not precious and can be overwritten by
    git.  Do you have ideas for wording that would help with that?
    This would be especially welcome if you can phrase them in the
    form of a patch against Documentation/gitignore.txt.

 2. Occasionally people have mentioned the idea of a .gitprecious file
    listing precious files that git should not track and not overwrite
    (e.g., keys and other configuration files, IDE state, or metadata
    for another version control system being used in parallel).  Would
    you be interested in working on that?

Thanks and hope that helps,
Jonathan

^ permalink raw reply	[relevance 5%]

* Re: Bug with .gitignore and branch switching
  @ 2017-03-17 21:23  6% ` Junio C Hamano
  2017-03-17 21:58  0%   ` Stefan Beller
                     ` (2 more replies)
  2017-03-17 21:54  5% ` Jonathan Nieder
  1 sibling, 3 replies; 200+ results
From: Junio C Hamano @ 2017-03-17 21:23 UTC (permalink / raw)
  To: Nevada Sanchez; +Cc: git

Nevada Sanchez <sanchez.nevada@gmail.com> writes:

> Here's an easy to reproduce bug. It's the only example I know of where
> git legitimately loses data in a way that is unrecoverable,
> unexpected, and without warning.

This is an example of a user explicitly telling git to discard data
and git performing as it is told.

There is no "untracked but precious" vs "untracked and expendable"
difference in the current system.  An untracked file that matches
patterns listed in .gitignore is treated as the latter.

When you have an untracked file that .gitignore knows about in the
working tree while you are on "feature", if switching to another
branch requires to remove that file, the content there is deemed
expendable, because the user said so by listing it in .gitignore.

We've discussed the lack of "untracked but precious" class a few
times on the list in the past, but I do not recall the topic came up
in the recent past.  It perhaps is because nobody found that class
useful enough so far.

^ permalink raw reply	[relevance 6%]

* [PATCH v2 0/2] Documentation: Link git-ls-files to core.quotePath variable.
  @ 2017-02-24 20:37  4% ` Andreas Heiduk
  0 siblings, 0 replies; 200+ results
From: Andreas Heiduk @ 2017-02-24 20:37 UTC (permalink / raw)
  To: gitster; +Cc: Andreas Heiduk, git

These two patches replace and extend the precious patches with the
same subject. Suggestions from Philip Oakley and Junio C Hamano are
included.

I tried to find and adjust all places where pathname quoting and "-z"
were described. I omitted these places:

* Here "-z" is for input only. Quoting is unclear to me.

-- git-mktree.txt
-- git-update-index.txt
-- git-checkout-index.txt

* Here pathname quoting is not mentioned:

-- git-check-ignore.txt
-- git-check-attr.txt

And last but not least: 

- git-grep.txt: The paths are always unquoted, `-z` toggles only the
delimiter. Perhaps some CAVEAT should be added.


Andreas Heiduk (2):
  Documentation: Improve description for core.quotePath
  Documentation: Link descriptions of -z to core.quotePath

 Documentation/config.txt              | 24 ++++++++++++++----------
 Documentation/diff-format.txt         |  7 ++++---
 Documentation/diff-generate-patch.txt |  7 +++----
 Documentation/diff-options.txt        |  7 +++----
 Documentation/git-apply.txt           |  7 +++----
 Documentation/git-commit.txt          |  9 ++++++---
 Documentation/git-ls-files.txt        | 10 ++++++----
 Documentation/git-ls-tree.txt         | 10 +++++++---
 Documentation/git-status.txt          |  7 +++----
 9 files changed, 49 insertions(+), 39 deletions(-)


^ permalink raw reply	[relevance 4%]

* Re: [PATCH/RFC] WIP: log: allow "-" as a short-hand for "previous branch"
  @ 2017-02-06 23:09  4%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2017-02-06 23:09 UTC (permalink / raw)
  To: Siddharth Kannan; +Cc: git, pranit.bauva, Matthieu.Moy, peff, pclouds, sandals

Siddharth Kannan <kannan.siddharth12@gmail.com> writes:

> Hey Junio, I did some more digging into the codepath:
> ...
> In case you would prefer for me to not work on this anymore
> because I am new to the codebase, I will leave it at this.

The above is nicely analized and summarized.

The earlier mention of "those new to the codebase" by me was "this
is an inappropriate topic as a GSoC microproject for people new to
the codebase" and it wasn't meant to say "this part of the code is
too precious to let unknown folks touch it."

The focus of GSoC being mentoring those who are new to the open
source development, and hopefully retain them in the community after
GSoC is over, we do expect microprojects to be suitable for those
who are new to the codebase.

The focus of microprojects are twofold.  It is a way for new people
to learn the way in which they will be interacting with the
community once they become Git developers, sending their patches
(which includes analyzing and explaining the problem they are trying
to solve and their solution to it) and receiving and responding to
review comments.  We also want to find out which candidates are
willing to learn and which ones are difficult to work with during
the process.  And its primary focus is not about solving the real
issues the project has with its code---something "bite-sized" is
sufficient (and desirable) for microprojects for both GSoC student
candidates and GSoC mentors and reviewers to work with.

> (c) -> Else look for "r1^-"
> ...
> Case (c) is a bit confusing. This could be something like "-^-", and
> something like "^-" could mean "Not commits on previous branch" or it
> could mean "All commits on this branch except for the parent of HEAD"

Do you mean:

    "git rev-parse ^-" does not mean "git rev-parse HEAD^-", but we
    probably would want to, and if that is what is going to happen,
    "^-" should mean "HEAD^-", and cannot be used for "^@{-1}"?

It's friend "^!" does not mean "HEAD^!", and "^@" does not mean
"HEAD^@", either (the latter is somewhat borked, though, and "^@"
translates to "^HEAD" because confusingly "@" stands for "HEAD"
sometimes).  

So my gut feeling is that it is probably OK to make "^-" mean
"^@{-1}"; it may be prudent to at least initially keep "^-" an error
like it currently is already, though.



^ permalink raw reply	[relevance 4%]

* Re: [PATCH 11/16] teach unpack_trees() to remove submodule contents
       [not found]       ` <20161117133538.GF39230@book.hvoigt.net>
@ 2016-11-18 19:25  0%     ` Stefan Beller
  0 siblings, 0 replies; 200+ results
From: Stefan Beller @ 2016-11-18 19:25 UTC (permalink / raw)
  To: Heiko Voigt
  Cc: git@vger.kernel.org, Brandon Williams, Junio C Hamano,
	Jonathan Nieder, Martin Fick, David Turner

On Thu, Nov 17, 2016 at 5:35 AM, Heiko Voigt <hvoigt@hvoigt.net> wrote:
> On Tue, Nov 15, 2016 at 03:06:46PM -0800, Stefan Beller wrote:
>> Extend rmdir_or_warn() to remove the directories of those submodules which
>> are scheduled for removal. Also teach verify_clean_submodule() to check
>> that a submodule configured to be removed is not modified before scheduling
>> it for removal.
>>
>> Signed-off-by: Stefan Beller <sbeller@google.com>
>> ---
> [...]
>> --- a/wrapper.c
>> +++ b/wrapper.c
>> @@ -2,6 +2,7 @@
>>   * Various trivial helper wrappers around standard functions
>>   */
>>  #include "cache.h"
>> +#include "submodule.h"
>>
>>  static void do_nothing(size_t size)
>>  {
>> @@ -592,6 +593,9 @@ int unlink_or_warn(const char *file)
>>
>>  int rmdir_or_warn(const char *file)
>>  {
>> +     if (submodule_is_interesting(file, null_sha1)
>> +         && depopulate_submodule(file))
>> +             return -1;
>
> How about untracked files inside submodules? Should we not care about
> them? With this code the entire directory will be removed. In general
> git would not remove a directory with untracked files in it even though
> it is removed in the database. I wonder if we should imitate that here
> and just remove files that are tracked by git so that users do not loose
> files that might be precious to them.

Well from the superprojects perspective a submodule looks like a file,
so if the checkout involved removing a file it had to either be clean or the
checkout failed. So I though we'd go with a similar way here?

We need to stop when untracked files are present, I am not sure if we need
to care if the files are ignored, though.

In this version of the series, the test added in patch 14, testing for
treating untracked files properly is a failing test. So I agree that we should
not just delete them; I'll fix that in the next version of the series.

Thanks,
Stefan

^ permalink raw reply	[relevance 0%]

* Re: Git issue - ignoring changes to tracked file with assume-unchanged
  @ 2016-11-07 22:34  4%     ` Jakub Narębski
  0 siblings, 0 replies; 200+ results
From: Jakub Narębski @ 2016-11-07 22:34 UTC (permalink / raw)
  To: Junio C Hamano, Jeff King; +Cc: Halde, Faiz, git@vger.kernel.org

W dniu 01.11.2016 o 19:11, Junio C Hamano pisze:
> Jeff King <peff@peff.net> writes:
>> On Tue, Nov 01, 2016 at 10:28:57AM +0000, Halde, Faiz wrote:
>>
>>> I frequently use the following command to ignore changes done in a file
>>>
>>> git update-index --assume-unchanged somefile
>>>
>>> Now when I do a pull from my remote branch and say the file 'somefile'
>>> was changed locally and in remote, git will abort the merge saying I
>>> need to commit my changes of 'somefile'.
>>>
>>> But isn't the whole point of the above command to ignore the changes
>>> within the file?
>>
>> No. The purpose of --assume-unchanged is to promise git that you will
>> not change the file, so that it may skip checking the file contents in
>> some cases as an optimization.
> 
> That's correct.  
> 
> The next anticipated question is "then how would I tell Git to
> ignore changes done to a file locally by me?", whose short answer is
> "You don't", of course.

Well, you can always use --skip-worktree.  It is a better fit than using
--assume-unchanged, because at least you wouldn't loose your precious
local changes (which happened to me).

OTOH it doesn't solve your issue of --skip-worktree / --assume-unchanged
blocking operation (pull in your case, stash is what I noticed problem
with when using --skip-worktree).

But --skip-worktree is still workaround...

-- 
Jakub Narębski


^ permalink raw reply	[relevance 4%]

* Re: Drastic jump in the time required for the test suite
  2016-10-20 10:50  4%     ` Johannes Schindelin
@ 2016-10-20 11:39  0%       ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2016-10-20 11:39 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, git

On Thu, Oct 20, 2016 at 12:50:32PM +0200, Johannes Schindelin wrote:

> That reflects my findings, too. I want to add that I found preciously
> little difference between running slow-to-fast and running in numeric
> order, so I gave up on optimizing on that front.

Interesting. It makes a 10-15% difference here.

I also point "--root" at a ram disk. The tests are very I/O heavy and
sometimes fsync; even on a system with an SSD, this saves another ~10%.

I know that's small potatoes compared to the Windows vs Linux times, but
it might be worth exploring.

> Further, I found that the Subversion tests (which run at the end) are so
> close in their running time that running the tests in parallel with -j5
> does not result in any noticeable improvement when reordered.

I normally don't run the Subversion tests at all. Installing cvs, cvsps,
subversion, and libsvn-perl nearly doubles the runtime of the test suite
for me (I imagine adding p4 to the mix would bump it further). While
it's certainly possible to break them with a change in core git, it
doesn't seem like a good tradeoff if I'm not touching them often.

As the GfW maintainer, you probably should be running them, at least
before a release. But cutting them might be a good way to speed up your
day-to-day runs.

I also use -j16 on a quad-core (+hyperthreads) machine, which I arrived
at experimentally. At least on Linux, it's definitely worth having more
threads than processors, to keep the processors busy.

> I guess I will have to bite into the sour apple and try to profile, say,
> t3404 somehow, including all the shell scripting stuff, to identify where
> exactly all that time is lost. My guess is that it boils down to
> gazillions of calls to programs like expr.exe or merely subshells.

I'm not so sure it isn't gazillions of calls to git. It is testing
rebase, after all, which is itself a shell script. GIT_TRACE_PERFORMANCE
gives sort of a crude measure; it reports only builtins (so it will
underestimate the total time spent in git), but it also doesn't make
clear which programs call which, so some times are double-counted (if a
builtin shells out to another builtin). But:

  $ export GIT_TRACE_PERFORMANCE=/tmp/foo.out
  $ rm /tmp/foo.out
  $ time ./t3404-rebase-interactive.sh
  real    0m29.755s
  user    0m1.444s
  sys     0m2.268s

  $ perl -lne '
      /performance: ([0-9.]+)/ and $total += $1;
      END { print $total }
    ' /tmp/foo.out
  32.851352624

Clearly that's not 100% accurate, as it claims we spent longer in git
than the script actually took to run. Given the caveats above, I'm not
even sure if it is in the right ballpark. But there are 11,000 git
builtins run as part of that script. Even at 2ms each, that's still most
of the time going to git.

And obviously the fix involves converting git-rebase, which you're
already working on. But it's not clear to me that the test
infrastructure or shell scripts are the primary cause of the slowness in
this particular case.

-Peff

^ permalink raw reply	[relevance 0%]

* Re: Drastic jump in the time required for the test suite
  @ 2016-10-20 10:50  4%     ` Johannes Schindelin
  2016-10-20 11:39  0%       ` Jeff King
  0 siblings, 1 reply; 200+ results
From: Johannes Schindelin @ 2016-10-20 10:50 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, git

Hi peff,

On Wed, 19 Oct 2016, Jeff King wrote:

> On Wed, Oct 19, 2016 at 10:32:12AM -0700, Junio C Hamano wrote:
> 
> > > Maybe we should start optimizing the tests...
> > 
> > Yup, two things that come to mind are to identify long ones and see if
> > each of them can be split into two halves that can be run in parallel,
> > and to go through the tests with fine toothed comb and remove the ones
> > that test exactly the same thing as another test.  The latter would be
> > very time consuming, though.
> 
> FWIW, I have made attempts at "split long ones into two" before, and
> didn't come up with much. There _are_ some tests that are much longer
> than others[1], but they are not longer than the whole suite takes to
> run. So running in slow-to-fast order means they start first, are run in
> parallel with the other tests, and the CPUs stay relatively full through
> the whole run.

That reflects my findings, too. I want to add that I found preciously
little difference between running slow-to-fast and running in numeric
order, so I gave up on optimizing on that front.

>     43.216765165329 t3404-rebase-interactive.sh
>     30.6568658351898 t3421-rebase-topology-linear.sh
>     27.92564702034 t9001-send-email.sh
>     15.5906939506531 t9500-gitweb-standalone-no-errors.sh
>     15.4882569313049 t6030-bisect-porcelain.sh
>     14.487174987793 t7610-mergetool.sh
>     13.8276169300079 t3425-rebase-topology-merges.sh
>     12.7450480461121 t3426-rebase-submodule.sh
>     12.4915001392365 t3415-rebase-autosquash.sh
>     11.8122401237488 t5572-pull-submodule.sh

That looks very similar to what I found: t3404 on top, followed by t3421.

Further, I found that the Subversion tests (which run at the end) are so
close in their running time that running the tests in parallel with -j5
does not result in any noticeable improvement when reordered.

I guess I will have to bite into the sour apple and try to profile, say,
t3404 somehow, including all the shell scripting stuff, to identify where
exactly all that time is lost. My guess is that it boils down to
gazillions of calls to programs like expr.exe or merely subshells.

Ciao,
Dscho

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] convert: mark a file-local symbol static
  @ 2016-10-17 20:48  4%                   ` Stefan Beller
  0 siblings, 0 replies; 200+ results
From: Stefan Beller @ 2016-10-17 20:48 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Ramsay Jones, Jeff King, Johannes Schindelin, Lars Schneider,
	GIT Mailing-list

On Mon, Oct 17, 2016 at 1:07 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Ramsay Jones <ramsay@ramsayjones.plus.com> writes:
>
>> Heh, I actually have the following in my config.mak already:
>>
>> extra-clean: clean
>>       find . -iname '*.o' -exec rm {} \;
>>
>> But for some reason I _always_ type 'make clean' and then, to top
>> it off, I _always_ type the 'find' command by hand (I have no idea
>> why) :-D
>
> "git clean -x" anybody?

I only want to cleanup compiled stuff and such, not the precious
unversioned text files I have laying around here. So I guess

  git clean -x -e:(attr:!binary)

would suffice, though. ;)

^ permalink raw reply	[relevance 4%]

* [PATCH v2] l10n: de.po: translate 260 new messages
  2016-10-02 16:59  1% [PATCH] l10n: de.po: translate 260 new messages Ralf Thielow
@ 2016-10-07 16:45  1% ` Ralf Thielow
  0 siblings, 0 replies; 200+ results
From: Ralf Thielow @ 2016-10-07 16:45 UTC (permalink / raw)
  To: git, matthias.ruester
  Cc: tr, jk, stimming, phillip.szelat, magnus.goerlitz, Ralf Thielow

Translate 260 new message came from git.pot updates in 9fa976f (l10n:
git.pot: v2.10.0 round 1 (248 new, 56 removed)) and 5bd166d (l10n:
git.pot: v2.10.0 round 2 (12 new, 44 removed)).

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 po/de.po | 783 ++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 421 insertions(+), 362 deletions(-)

diff --git a/po/de.po b/po/de.po
index e1865c6ca..0755cdf6c 100644
--- a/po/de.po
+++ b/po/de.po
@@ -14,72 +14,60 @@ msgstr ""
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n!=1);\n"
 
 #: advice.c:55
 #, c-format
 msgid "hint: %.*s\n"
 msgstr "Hinweis: %.*s\n"
 
 #: advice.c:83
-#, fuzzy
 msgid "Cherry-picking is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Cherry-Picken ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:85
-#, fuzzy
 msgid "Committing is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Committen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:87
-#, fuzzy
 msgid "Merging is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Mergen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:89
-#, fuzzy
 msgid "Pulling is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Pullen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:91
-#, fuzzy
 msgid "Reverting is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Reverten ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:93
-#, fuzzy, c-format
+#, c-format
 msgid "It is not possible to %s because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "%s ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:101
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
 "as appropriate to mark resolution and make a commit."
 msgstr ""
 "Korrigieren Sie dies im Arbeitsverzeichnis, und benutzen Sie\n"
 "dann 'git add/rm <Datei>', um die Auflösung entsprechend zu markieren\n"
 "und zu committen."
 
 #: advice.c:109
-#, fuzzy
 msgid "Exiting because of an unresolved conflict."
-msgstr "Beende wegen nicht abgeschlossenem Merge."
+msgstr "Beende wegen unaufgelöstem Konflikt."
 
 #: advice.c:114 builtin/merge.c:1181
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert)."
 
 #: advice.c:116
 msgid "Please, commit your changes before merging."
 msgstr "Bitte committen Sie Ihre Änderungen, bevor Sie mergen."
 
 #: advice.c:117
 msgid "Exiting because of unfinished merge."
 msgstr "Beende wegen nicht abgeschlossenem Merge."
@@ -90,24 +78,38 @@ msgid ""
 "Note: checking out '%s'.\n"
 "\n"
 "You are in 'detached HEAD' state. You can look around, make experimental\n"
 "changes and commit them, and you can discard any commits you make in this\n"
 "state without impacting any branches by performing another checkout.\n"
 "\n"
 "If you want to create a new branch to retain commits you create, you may\n"
 "do so (now or later) by using -b with the checkout command again. Example:\n"
 "\n"
 "  git checkout -b <new-branch-name>\n"
 "\n"
 msgstr ""
+"Hinweis: Checke '%s' aus.\n"
+"\n"
+"Sie befinden sich im Zustand eines 'lösgelösten HEAD'. Sie können sich\n"
+"umschauen, experimentelle Änderungen vornehmen und diese committen, und\n"
+"Sie können alle möglichen Commits, die Sie in diesem Zustand machen,\n"
+"ohne Auswirkungen auf irgendeinen Branch verwerfen, indem Sie einen\n"
+"weiteren Checkout durchführen.\n"
+"\n"
+"Wenn Sie einen neuen Branch erstellen möchten, um Ihre erstellten Commits\n"
+"zu behalten, können Sie das (jetzt oder später) durch einen weiteren Checkout\n"
+"mit der Option -b tun. Beispiel:\n"
+"\n"
+"  git checkout -b <neuer-Branchname>\n"
+"\n"
 
 #: archive.c:12
 msgid "git archive [<options>] <tree-ish> [<path>...]"
 msgstr "git archive [<Optionen>] <Commit-Referenz> [<Pfad>...]"
 
 #: archive.c:13
 msgid "git archive --list"
 msgstr "git archive --list"
 
 #: archive.c:14
 msgid ""
 "git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
@@ -185,165 +187,176 @@ msgstr "Repository"
 msgid "retrieve the archive from remote repository <repo>"
 msgstr "Archiv vom Remote-Repository <Repository> abrufen"
 
 #: archive.c:453 builtin/archive.c:92 builtin/notes.c:483
 msgid "command"
 msgstr "Programm"
 
 #: archive.c:454 builtin/archive.c:93
 msgid "path to the remote git-upload-archive command"
 msgstr "Pfad zum externen \"git-upload-archive\"-Programm"
 
 #: archive.c:461
-#, fuzzy
 msgid "Unexpected option --remote"
-msgstr "unerwarteter Modus $mod_dst"
+msgstr "Unerwartete Option --remote"
 
 #: archive.c:463
-#, fuzzy
 msgid "Option --exec can only be used together with --remote"
-msgstr ""
-"Die Option --ignore-missing kann nur zusammen mit --dry-run verwendet werden."
+msgstr "Die Option --exec kann nur zusammen mit --remote verwendet werden."
 
 #: archive.c:465
 msgid "Unexpected option --output"
-msgstr ""
+msgstr "Unerwartete Option --output"
 
 #: archive.c:487
-#, fuzzy, c-format
+#, c-format
 msgid "Unknown archive format '%s'"
-msgstr "Unbekanntes %.*s Format %s"
+msgstr "Unbekanntes Archivformat '%s'"
 
 #: archive.c:494
-#, fuzzy, c-format
+#, c-format
 msgid "Argument not supported for format '%s': -%d"
-msgstr "Kann \"reflog\" für '%s' nicht durchführen: %s\n"
+msgstr "Argument für Format '%s' nicht unterstützt: -%d"
 
 #: attr.c:263
 msgid ""
 "Negative patterns are ignored in git attributes\n"
 "Use '\\!' for literal leading exclamation."
 msgstr ""
 "Verneinende Muster werden in Git-Attributen ignoriert.\n"
 "Benutzen Sie '\\!' für führende Ausrufezeichen."
 
 #: bisect.c:441
-#, fuzzy, c-format
+#, c-format
 msgid "Could not open file '%s'"
-msgstr "Konnte '%s' nicht öffnen"
+msgstr "Konnte Datei '%s' nicht öffnen"
 
 #: bisect.c:446
-#, fuzzy, c-format
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
-msgstr "Notizinhalte in einer Datei"
+msgstr "Ungültiger Inhalt bzgl. Anführungsstriche in Datei '%s': %s"
 
 #: bisect.c:655
-#, fuzzy, c-format
+#, c-format
 msgid "We cannot bisect more!\n"
-msgstr "keine binäre Suche im Gange"
+msgstr "Keine binäre Suche mehr möglich!\n"
 
 #: bisect.c:708
-#, fuzzy, c-format
+#, c-format
 msgid "Not a valid commit name %s"
-msgstr "%s ist kein gültiger Objekt-Name"
+msgstr "%s ist kein gültiger Commit-Name"
 
 #: bisect.c:732
 #, c-format
 msgid ""
 "The merge base %s is bad.\n"
 "This means the bug has been fixed between %s and [%s].\n"
 msgstr ""
+"Die Merge-Basis %s ist fehlerhaft.\n"
+"Das bedeutet, der Fehler wurde zwischen %s und [%s] behoben.\n"
 
 #: bisect.c:737
 #, c-format
 msgid ""
 "The merge base %s is new.\n"
 "The property has changed between %s and [%s].\n"
 msgstr ""
+"Die Merge-Basis %s ist neu.\n"
+"Das bedeutet, die Eigenschaft hat sich zwischen %s und [%s] geändert.\n"
 
 #: bisect.c:742
 #, c-format
 msgid ""
 "The merge base %s is %s.\n"
 "This means the first '%s' commit is between %s and [%s].\n"
 msgstr ""
+"Die Merge-Basis %s ist %s.\n"
+"Das bedeutet, der erste '%s' Commit befindet sich zwischen %s und [%s]\n"
 
 #: bisect.c:750
 #, c-format
 msgid ""
 "Some %s revs are not ancestor of the %s rev.\n"
 "git bisect cannot work properly in this case.\n"
 "Maybe you mistook %s and %s revs?\n"
 msgstr ""
+"Manche %s Commits sind keine Vorgänger des %s Commits.\n"
+"git bisect kann in diesem Fall nicht richtig arbeiten.\n"
+"Vielleicht verwechselten Sie %s und %s Commits?\n"
 
 #: bisect.c:763
 #, c-format
 msgid ""
 "the merge base between %s and [%s] must be skipped.\n"
 "So we cannot be sure the first %s commit is between %s and %s.\n"
 "We continue anyway."
 msgstr ""
+"Die Merge-Basis zwischen %s und [%s] muss ausgelassen werden.\n"
+"Es kann daher nicht sichergestellt werden, dass sich der\n"
+"erste %s Commit zwischen %s und %s befindet.\n"
+"Es wird dennoch fortgesetzt."
 
 #: bisect.c:798
 #, c-format
 msgid "Bisecting: a merge base must be tested\n"
-msgstr ""
+msgstr "binäre Suche: eine Merge-Basis muss geprüft werden\n"
 
 #: bisect.c:849
-#, fuzzy, c-format
+#, c-format
 msgid "a %s revision is needed"
-msgstr "%.*s ist zum Commit vorgemerkt"
+msgstr "ein %s Commit wird benötigt"
 
 #: bisect.c:866 builtin/notes.c:174 builtin/tag.c:248
 #, c-format
 msgid "could not create file '%s'"
 msgstr "konnte Datei '%s' nicht erstellen"
 
 #: bisect.c:917
-#, fuzzy, c-format
+#, c-format
 msgid "could not read file '%s'"
-msgstr "Konnte Log-Datei '%s' nicht lesen"
+msgstr "Konnte Datei '%s' nicht lesen"
 
 #: bisect.c:947
-#, fuzzy
 msgid "reading bisect refs failed"
-msgstr "Hinzufügen von Dateien fehlgeschlagen"
+msgstr "Lesen von Referenzen für binäre Suche fehlgeschlagen"
 
 #: bisect.c:967
-#, fuzzy, c-format
+#, c-format
 msgid "%s was both %s and %s\n"
-msgstr "%s folgt sowohl %s als auch %s"
+msgstr "%s war sowohl %s als auch %s\n"
 
 #: bisect.c:975
 #, c-format
 msgid ""
 "No testable commit found.\n"
 "Maybe you started with bad path parameters?\n"
 msgstr ""
+"Kein testbarer Commit gefunden.\n"
+"Vielleicht starteten Sie mit falschen Pfad-Parametern?\n"
 
 #: bisect.c:994
 #, c-format
 msgid "(roughly %d step)"
 msgid_plural "(roughly %d steps)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "(ungefähr %d Schritt)"
+msgstr[1] "(ungefähr %d Schritte)"
 
 #. TRANSLATORS: the last %s will be replaced with
 #. "(roughly %d steps)" translation
 #: bisect.c:998
 #, c-format
 msgid "Bisecting: %d revision left to test after this %s\n"
 msgid_plural "Bisecting: %d revisions left to test after this %s\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "binäre Suche: danach noch %d Commit zum Testen übrig %s\n"
+msgstr[1] "binäre Suche: danach noch %d Commits zum Testen übrig %s\n"
 
 #: branch.c:53
 #, c-format
 msgid ""
 "\n"
 "After fixing the error cause you may try to fix up\n"
 "the remote tracking information by invoking\n"
 "\"git branch --set-upstream-to=%s%s%s\"."
 msgstr ""
 "\n"
 "Nachdem Sie die Fehlerursache behoben haben, können Sie\n"
 "die Tracking-Informationen mit\n"
@@ -571,120 +584,117 @@ msgid "could not parse %s"
 msgstr "konnte %s nicht parsen"
 
 #: commit.c:42
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s ist kein Commit!"
 
 #: compat/obstack.c:406 compat/obstack.c:408
 msgid "memory exhausted"
 msgstr "Speicher verbraucht"
 
 #: config.c:516
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in blob %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Blob %s"
 
 #: config.c:520
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in file %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Datei %s"
 
 #: config.c:524
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in standard input"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Standard-Eingabe"
 
 #: config.c:528
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in submodule-blob %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Submodul-Blob %s"
 
 #: config.c:532
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in command line %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Kommandozeile %s"
 
 #: config.c:536
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in %s"
 
 #: config.c:655
-#, fuzzy
 msgid "out of range"
-msgstr "Kein Commit-Bereich."
+msgstr "Außerhalb des Bereichs"
 
 #: config.c:655
-#, fuzzy
 msgid "invalid unit"
-msgstr "Ungültiger Objekt-Typ %s"
+msgstr "Ungültige Einheit"
 
 #: config.c:661
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s': %s"
 msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s': %s"
 
 #: config.c:666
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Blob %s: %s"
 
 #: config.c:669
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in file %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Datei %s: %s"
 
 #: config.c:672
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in standard input: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Standard-Eingabe: %s"
 
 #: config.c:675
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Submodul-Blob %s: %s"
 
 #: config.c:678
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Befehlszeile %s: %s"
 
 #: config.c:681
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s: %s"
 
 #: config.c:768
 #, c-format
 msgid "failed to expand user dir in: '%s'"
 msgstr "Fehler beim Erweitern des Nutzerverzeichnisses in: '%s'"
 
 #: config.c:849 config.c:860
 #, c-format
 msgid "bad zlib compression level %d"
 msgstr "ungültiger zlib Komprimierungsgrad %d"
 
 #: config.c:978
 #, c-format
 msgid "invalid mode for object creation: %s"
 msgstr "Ungültiger Modus für Objekterstellung: %s"
 
 #: config.c:1312
 msgid "unable to parse command-line config"
 msgstr ""
 "Konnte die über die Befehlszeile angegebene Konfiguration nicht parsen."
 
 #: config.c:1362
-#, fuzzy
 msgid "unknown error occurred while reading the configuration files"
 msgstr ""
 "Es trat ein unbekannter Fehler beim Lesen der Konfigurationsdateien auf."
 
 #: config.c:1716
 #, c-format
 msgid "unable to parse '%s' from command-line config"
 msgstr ""
 "Konnte Wert '%s' aus der über die Befehlszeile angegebenen Konfiguration\n"
 "nicht parsen."
 
 #: config.c:1718
@@ -854,27 +864,26 @@ msgstr "Fehler beim Sammeln von Namen und Informationen zum Kernel"
 
 #: dir.c:1942
 msgid "Untracked cache is disabled on this system or location."
 msgstr ""
 "Cache für unversionierte Dateien ist auf diesem System oder\n"
 "für dieses Verzeichnis deaktiviert."
 
 #: gpg-interface.c:178
 msgid "gpg failed to sign the data"
 msgstr "gpg beim Signieren der Daten fehlgeschlagen"
 
 #: gpg-interface.c:208
-#, fuzzy
 msgid "could not create temporary file"
-msgstr "konnte temporäre Datei '%s' nicht erstellen"
+msgstr "konnte temporäre Datei nicht erstellen"
 
 #: gpg-interface.c:210
 #, c-format
 msgid "failed writing detached signature to '%s'"
 msgstr "Fehler beim Schreiben der losgelösten Signatur nach '%s'"
 
 #: grep.c:1792
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "'%s': konnte %s nicht lesen"
 
 #: grep.c:1809 builtin/clone.c:382 builtin/diff.c:84 builtin/rm.c:155
@@ -1019,32 +1028,32 @@ msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
 
 #: merge-recursive.c:796
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "kann Objekt %s '%s' nicht lesen"
 
 #: merge-recursive.c:798
 #, c-format
 msgid "blob expected for %s '%s'"
 msgstr "Blob erwartet für %s '%s'"
 
 #: merge-recursive.c:822
-#, fuzzy, c-format
+#, c-format
 msgid "failed to open '%s': %s"
-msgstr "Fehler beim Öffnen von '%s'"
+msgstr "Fehler beim Öffnen von '%s': %s"
 
 #: merge-recursive.c:833
-#, fuzzy, c-format
+#, c-format
 msgid "failed to symlink '%s': %s"
-msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'"
+msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s': %s"
 
 #: merge-recursive.c:838
 #, c-format
 msgid "do not know what to do with %06o %s '%s'"
 msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
 
 #: merge-recursive.c:978
 msgid "Failed to execute internal merge"
 msgstr "Fehler bei Ausführung des internen Merges"
 
 #: merge-recursive.c:982
 #, c-format
@@ -1697,28 +1706,26 @@ msgstr ""
 msgid ""
 "not sending a push certificate since the receiving end does not support --"
 "signed push"
 msgstr ""
 "kein Versand des \"push\"-Zertifikates, da die Gegenseite keinen signierten\n"
 "Versand (\"--signed push\") unterstützt"
 
 #: send-pack.c:425
 msgid "the receiving end does not support --atomic push"
 msgstr "die Gegenseite unterstützt keinen atomaren Versand (\"--atomic push\")"
 
 #: send-pack.c:430
-#, fuzzy
 msgid "the receiving end does not support push options"
-msgstr ""
-"die Gegenseite unterstützt keinen signierten Versand (\"--signed push\")"
+msgstr "die Gegenseite unterstützt keine Push-Optionen"
 
 #: sequencer.c:174
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
 "nach Auflösung der Konflikte, markieren Sie die korrigierten Pfade\n"
 "mit 'git add <Pfade>' oder 'git rm <Pfade>'"
 
 #: sequencer.c:177
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
@@ -1745,27 +1752,27 @@ msgstr ""
 "Ihre lokalen Änderungen würden durch den Cherry-Pick überschrieben werden."
 
 #: sequencer.c:210
 msgid "Your local changes would be overwritten by revert."
 msgstr "Ihre lokalen Änderungen würden durch den Revert überschrieben werden."
 
 #: sequencer.c:213
 msgid "Commit your changes or stash them to proceed."
 msgstr ""
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\", um fortzufahren."
 
 #: sequencer.c:228
-#, fuzzy, c-format
+#, c-format
 msgid "%s: fast-forward"
-msgstr "Vorspulen erlauben"
+msgstr "%s: Vorspulen"
 
 #. TRANSLATORS: %s will be "revert" or "cherry-pick"
 #: sequencer.c:303
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: Konnte neue Index-Datei nicht schreiben"
 
 #: sequencer.c:321
 msgid "Could not resolve HEAD commit\n"
 msgstr "Konnte Commit von HEAD nicht auflösen\n"
 
 #: sequencer.c:341
@@ -1829,44 +1836,38 @@ msgstr "leere Menge von Commits übergeben"
 
 #: sequencer.c:641
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: Fehler beim Lesen des Index"
 
 #: sequencer.c:645
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: Fehler beim Aktualisieren des Index"
 
 #: sequencer.c:705
-#, fuzzy
 msgid "Cannot revert during another revert."
-msgstr "Kann Zustand des Arbeitsverzeichnisses nicht aufzeichnen"
+msgstr "Kann Revert nicht während eines anderen Reverts ausführen."
 
 #: sequencer.c:706
-#, fuzzy
 msgid "Cannot revert during a cherry-pick."
-msgstr ""
-"Kann keinen Teil-Commit durchführen, während \"cherry-pick\" im Gange ist."
+msgstr "Kann Revert nicht während eines Cherry-Picks ausführen."
 
 #: sequencer.c:709
-#, fuzzy
 msgid "Cannot cherry-pick during a revert."
-msgstr "kein \"cherry-pick\" oder \"revert\" im Gang"
+msgstr "Kann Cherry-Pick nicht während eines Reverts ausführen."
 
 #: sequencer.c:710
-#, fuzzy
 msgid "Cannot cherry-pick during another cherry-pick."
-msgstr ""
-"Kann keinen Teil-Commit durchführen, während \"cherry-pick\" im Gange ist."
+msgstr "Kann Cherry-Pick nicht während eines anderen Cherry-Picks ausführen."
 
 #: sequencer.c:732
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Konnte Zeile %d nicht parsen."
 
 #: sequencer.c:737
 msgid "No commits parsed."
 msgstr "Keine Commits geparst."
 
 #: sequencer.c:749
 #, c-format
@@ -1958,87 +1959,100 @@ msgid "%s: bad revision"
 msgstr "%s: ungültiger Commit"
 
 #: sequencer.c:1102
 msgid "Can't revert as initial commit"
 msgstr "Kann nicht als allerersten Commit einen Revert ausführen."
 
 #: setup.c:160
 #, c-format
 msgid ""
 "%s: no such path in the working tree.\n"
 "Use 'git <command> -- <path>...' to specify paths that do not exist locally."
 msgstr ""
+"%s: kein solcher Pfad im Arbeitsverzeichnis.\n"
+"Benutzen Sie 'git <Befehl> -- <Pfad>...' zur Angabe von Pfaden, die lokal\n"
+"nicht existieren."
 
 #: setup.c:173
 #, c-format
 msgid ""
 "ambiguous argument '%s': unknown revision or path not in the working tree.\n"
 "Use '--' to separate paths from revisions, like this:\n"
 "'git <command> [<revision>...] -- [<file>...]'"
 msgstr ""
+"mehrdeutiges Argument '%s': unbekannter Commit oder Pfad existiert nicht\n"
+"im Arbeitsverzeichnis\n"
+"Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:\n"
+"'git <Befehl> [<Commit>...] -- [<Datei>...]'"
 
 #: setup.c:223
 #, c-format
 msgid ""
 "ambiguous argument '%s': both revision and filename\n"
 "Use '--' to separate paths from revisions, like this:\n"
 "'git <command> [<revision>...] -- [<file>...]'"
 msgstr ""
+"mehrdeutiges Argument '%s': sowohl Commit als auch Dateiname\n"
+"Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:\n"
+"'git <Befehl> [<Commit>...] -- [<Datei>...]'"
 
 #: setup.c:248 builtin/apply.c:3362 builtin/apply.c:3373 builtin/apply.c:3419
 #, c-format
 msgid "failed to read %s"
 msgstr "Fehler beim Lesen von %s"
 
 #: setup.c:468
 #, c-format
 msgid "Expected git repo version <= %d, found %d"
 msgstr "Erwartete Git-Repository-Version <= %d, %d gefunden"
 
 #: setup.c:476
 msgid "unknown repository extensions found:"
 msgstr "Unbekannte Repository-Erweiterungen gefunden:"
 
 #: setup.c:762
 #, c-format
 msgid "Not a git repository (or any of the parent directories): %s"
-msgstr ""
+msgstr "Kein Git-Repository (oder irgendein Elternverzeichnis): %s"
 
 #: setup.c:764 setup.c:915 builtin/index-pack.c:1641
 msgid "Cannot come back to cwd"
 msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln"
 
 #: setup.c:845
-#, fuzzy
 msgid "Unable to read current working directory"
-msgstr "Konnte aktuelles Arbeitsverzeichnis nicht bekommen."
+msgstr "Konnte aktuelles Arbeitsverzeichnis nicht lesen."
 
 #: setup.c:920
 #, c-format
 msgid ""
 "Not a git repository (or any parent up to mount point %s)\n"
 "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
 msgstr ""
+"Kein Git-Repository (oder irgendein Elternverzeichnis bis zum Einhängepunkt %s)\n"
+"Stoppe bei Dateisystemgrenze (GIT_DISCOVERY_ACROSS_FILESYSTEM nicht gesetzt)."
 
 #: setup.c:927
-#, fuzzy, c-format
+#, c-format
 msgid "Cannot change to '%s/..'"
-msgstr "kann nicht in Verzeichnis %s wechseln"
+msgstr "Kann nicht in Verzeichnis '%s/..' wechseln"
 
 #: setup.c:989
 #, c-format
 msgid ""
 "Problem with core.sharedRepository filemode value (0%.3o).\n"
 "The owner of files must always have read and write permissions."
 msgstr ""
+"Problem mit Wert für Dateimodus (0%.3o) von core.sharedRepository.\n"
+"Der Besitzer der Dateien muss immer Lese- und Schreibrechte haben."
 
 #: sha1_file.c:1046
 msgid "offset before end of packfile (broken .idx?)"
 msgstr "Offset vor Ende der Packdatei (fehlerhafte Indexdatei?)"
 
 #: sha1_file.c:2434
 #, c-format
 msgid "offset before start of pack index for %s (corrupt index?)"
 msgstr "Offset vor Beginn des Pack-Index für %s (beschädigter Index?)"
 
 #: sha1_file.c:2438
 #, c-format
@@ -2150,109 +2164,121 @@ msgid "file %s is not writable by user"
 msgstr "Datei %s ist vom Benutzer nicht beschreibbar."
 
 #: trailer.c:873
 msgid "could not open temporary file"
 msgstr "konnte temporäre Datei '%s' nicht öffnen"
 
 #: trailer.c:912
 #, c-format
 msgid "could not rename temporary file to %s"
 msgstr "konnte temporäre Datei nicht zu %s umbenennen"
 
 #: transport.c:62
-#, fuzzy, c-format
+#, c-format
 msgid "Would set upstream of '%s' to '%s' of '%s'\n"
-msgstr "Konnte Sektion '%s' in Konfiguration nicht nach '%s' umbenennen"
+msgstr "Würde Upstream-Branch von '%s' zu '%s' von '%s' setzen\n"
 
 #: transport.c:151
-#, fuzzy, c-format
+#, c-format
 msgid "transport: invalid depth option '%s'"
-msgstr "Ungültige Option für --decorate: %s"
+msgstr "transport: ungültige --depth Option '%s'"
 
 #: transport.c:771
 #, c-format
 msgid ""
 "The following submodule paths contain changes that can\n"
 "not be found on any remote:\n"
 msgstr ""
+"Die folgenden Submodul-Pfade enthalten Änderungen, die in keinem\n"
+"Remote-Repository gefunden wurden:\n"
 
 #: transport.c:775
 #, c-format
 msgid ""
 "\n"
 "Please try\n"
 "\n"
 "\tgit push --recurse-submodules=on-demand\n"
 "\n"
 "or cd to the path and use\n"
 "\n"
 "\tgit push\n"
 "\n"
 "to push them to a remote.\n"
 "\n"
 msgstr ""
+"\n"
+"Bitte versuchen Sie\n"
+"\n"
+"\tgit push --recurse-submodules=on-demand\n"
+"\n"
+"oder wechseln Sie in das Verzeichnis und benutzen Sie\n"
+"\n"
+"\tgit push\n"
+"\n"
+"zum Versenden zu einem Remote-Repository.\n"
+"\n"
 
 #: transport.c:783
-#, fuzzy
 msgid "Aborting."
-msgstr "Abbruch\n"
+msgstr "Abbruch."
 
 #: transport-helper.c:1041
 #, c-format
 msgid "Could not read ref %s"
 msgstr "Konnte Referenz %s nicht lesen."
 
 #: unpack-trees.c:64
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
 "%%sPlease commit your changes or stash them before you switch branches."
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden beim Auschecken\n"
 "überschrieben werden:\n"
-"%%sBitte committen oder stashen Sie Ihre Änderungen, bevor Sie Branches "
+"%%sBitte committen oder stashen Sie Ihre Änderungen, bevor Sie Branches\n"
 "wechseln."
 
 #: unpack-trees.c:66
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
 "%%s"
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden beim Auschecken\n"
 "überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:69
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
 "%%sPlease commit your changes or stash them before you merge."
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
 "überschrieben werden:\n"
 "%%sBitte committen oder stashen Sie Ihre Änderungen, bevor sie mergen."
 
 #: unpack-trees.c:71
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
 "%%s"
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
 "überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:74
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
 "%%sPlease commit your changes or stash them before you %s."
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden durch %s\n"
 "überschrieben werden:\n"
 "%%sBitte committen oder stashen Sie Ihre Änderungen, bevor Sie %s ausführen."
 
 #: unpack-trees.c:76
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
@@ -2263,143 +2289,136 @@ msgstr ""
 
 #: unpack-trees.c:81
 #, c-format
 msgid ""
 "Updating the following directories would lose untracked files in it:\n"
 "%s"
 msgstr ""
 "Durch die Aktualisierung der folgenden Verzeichnisse würden unversionierte\n"
 "Dateien in diesen Verzeichnissen verloren gehen:\n"
 "%s"
 
 #: unpack-trees.c:85
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
 "%%sPlease move or remove them before you switch branches."
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
 "den Checkout entfernt werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor Sie Branches wechseln."
 
 #: unpack-trees.c:87
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "Checkout entfernt werden:\n"
 "%%s"
 
 #: unpack-trees.c:90
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be removed by merge:\n"
 "%%sPlease move or remove them before you merge."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Merge entfernt werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Merge entfernt werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor sie mergen."
 
 #: unpack-trees.c:92
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by merge:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "Merge entfernt werden:\n"
 "%%s"
 
 #: unpack-trees.c:95
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be removed by %s:\n"
 "%%sPlease move or remove them before you %s."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"%s entfernt werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den %s entfernt werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor sie %s ausführen."
 
 #: unpack-trees.c:97
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by %s:\n"
 "%%s"
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"%s entfernt werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den %s entfernt werden:\n"
 "%%s"
 
 #: unpack-trees.c:102
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by "
 "checkout:\n"
 "%%sPlease move or remove them before you switch branches."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Checkout überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Checkout überschrieben werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor Sie Branches wechseln."
 
 #: unpack-trees.c:104
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by "
 "checkout:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "Checkout überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:107
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
 "%%sPlease move or remove them before you merge."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Merge überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Merge überschrieben werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor Sie mergen."
 
 #: unpack-trees.c:109
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
 "%%s"
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Merge überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Merge überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:112
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
 "%%sPlease move or remove them before you %s."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"%s überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den %s überschrieben werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor sie %s ausführen."
 
 #: unpack-trees.c:114
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "%s überschrieben werden:\n"
 "%%s"
@@ -2472,27 +2491,27 @@ msgstr "eine 'file:' URL darf keine Portnummer enthalten"
 msgid "invalid characters in host name"
 msgstr "Hostname enthält ungültige Zeichen"
 
 #: urlmatch.c:244 urlmatch.c:255
 msgid "invalid port number"
 msgstr "ungültige Portnummer"
 
 #: urlmatch.c:322
 msgid "invalid '..' path segment"
 msgstr "ungültiges '..' Pfadsegment"
 
 #: worktree.c:282
-#, fuzzy, c-format
+#, c-format
 msgid "failed to read '%s'"
-msgstr "Fehler beim Lesen von %s"
+msgstr "Fehler beim Lesen von '%s'"
 
 #: wrapper.c:222 wrapper.c:392
 #, c-format
 msgid "could not open '%s' for reading and writing"
 msgstr "Konnte '%s' nicht zum Lesen und Schreiben öffnen."
 
 #: wrapper.c:224 wrapper.c:394 builtin/am.c:778
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "Konnte '%s' nicht zum Schreiben öffnen."
 
 #: wrapper.c:226 wrapper.c:396 builtin/am.c:324 builtin/am.c:771
@@ -2682,29 +2701,26 @@ msgstr ""
 "Ändern Sie nicht die obige Zeile.\n"
 "Alles unterhalb von ihr wird entfernt."
 
 #: wt-status.c:950
 msgid "You have unmerged paths."
 msgstr "Sie haben nicht zusammengeführte Pfade."
 
 #: wt-status.c:953
 msgid "  (fix conflicts and run \"git commit\")"
 msgstr " (beheben Sie die Konflikte und führen Sie \"git commit\" aus)"
 
 #: wt-status.c:955
-#, fuzzy
 msgid "  (use \"git merge --abort\" to abort the merge)"
-msgstr ""
-"  (benutzen Sie \"git am --abort\", um den ursprünglichen Branch "
-"wiederherzustellen)"
+msgstr "  (benutzen Sie \"git merge --abort\", um den Merge abzubrechen)"
 
 #: wt-status.c:960
 msgid "All conflicts fixed but you are still merging."
 msgstr "Alle Konflikte sind behoben, aber Sie sind immer noch beim Merge."
 
 #: wt-status.c:963
 msgid "  (use \"git commit\" to conclude merge)"
 msgstr "  (benutzen Sie \"git commit\", um den Merge abzuschließen)"
 
 #: wt-status.c:973
 msgid "You are in the middle of an am session."
 msgstr "Eine \"am\"-Sitzung ist im Gange."
@@ -2984,25 +3000,25 @@ msgstr ""
 #, c-format
 msgid "nothing to commit\n"
 msgstr "nichts zu committen\n"
 
 #: wt-status.c:1557
 #, c-format
 msgid "nothing to commit (use -u to show untracked files)\n"
 msgstr ""
 "nichts zu committen (benutzen Sie die Option -u, um unversionierte Dateien "
 "anzuzeigen)\n"
 
 #: wt-status.c:1561
-#, fuzzy, c-format
+#, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
 
 #: wt-status.c:1668
 msgid "Initial commit on "
 msgstr "Initialer Commit auf "
 
 #: wt-status.c:1672
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Branch)"
 
 #: wt-status.c:1701
@@ -3161,25 +3177,25 @@ msgstr "Hinzufügen von Dateien fehlgeschlagen"
 #: builtin/add.c:336
 msgid "-A and -u are mutually incompatible"
 msgstr "Die Optionen -A und -u sind zueinander inkompatibel."
 
 #: builtin/add.c:343
 msgid "Option --ignore-missing can only be used together with --dry-run"
 msgstr ""
 "Die Option --ignore-missing kann nur zusammen mit --dry-run verwendet werden."
 
 #: builtin/add.c:352
 #, c-format
 msgid "--chmod param '%s' must be either -x or +x"
-msgstr ""
+msgstr "--chmod Parameter '%s' muss entweder -x oder +x sein"
 
 #: builtin/add.c:367
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
 
 #: builtin/add.c:368
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "Meinten Sie vielleicht 'git add .'?\n"
 
 #: builtin/add.c:373 builtin/check-ignore.c:172 builtin/checkout.c:279
@@ -4468,34 +4484,33 @@ msgstr "falsch benannten Branch '%s' umbenannt"
 #: builtin/branch.c:597
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr "Branch umbenannt zu %s, aber HEAD ist nicht aktualisiert!"
 
 #: builtin/branch.c:604
 msgid "Branch is renamed, but update of config-file failed"
 msgstr ""
 "Branch ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
 "fehlgeschlagen."
 
 #: builtin/branch.c:620
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Please edit the description for the branch\n"
 "  %s\n"
 "Lines starting with '%c' will be stripped.\n"
 msgstr ""
-"\n"
-"Geben Sie eine Beschreibung für Tag\n"
+"Bitte ändern Sie die Beschreibung für den Branch\n"
 "  %s\n"
-"ein. Zeilen, die mit '%c' beginnen, werden ignoriert.\n"
+"Zeilen, die mit '%c' beginnen, werden entfernt.\n"
 
 #: builtin/branch.c:651
 msgid "Generic options"
 msgstr "Allgemeine Optionen"
 
 #: builtin/branch.c:653
 msgid "show hash and subject, give twice for upstream branch"
 msgstr "Hash und Betreff anzeigen; -vv: zusätzlich Upstream-Branch"
 
 #: builtin/branch.c:654
 msgid "suppress informational messages"
 msgstr "Informationsmeldungen unterdrücken"
@@ -6313,27 +6328,26 @@ msgstr "die angegebenen Dateien zusätzlich zum Commit vormerken"
 msgid "interactively add files"
 msgstr "interaktives Hinzufügen von Dateien"
 
 #: builtin/commit.c:1618
 msgid "interactively add changes"
 msgstr "interaktives Hinzufügen von Änderungen"
 
 #: builtin/commit.c:1619
 msgid "commit only specified files"
 msgstr "nur die angegebenen Dateien committen"
 
 #: builtin/commit.c:1620
-#, fuzzy
 msgid "bypass pre-commit and commit-msg hooks"
-msgstr "\"pre-commit hook\" umgehen"
+msgstr "Hooks pre-commit und commit-msg umgehen"
 
 #: builtin/commit.c:1621
 msgid "show what would be committed"
 msgstr "anzeigen, was committet werden würde"
 
 #: builtin/commit.c:1632
 msgid "amend previous commit"
 msgstr "vorherigen Commit ändern"
 
 #: builtin/commit.c:1633
 msgid "bypass post-rewrite hook"
 msgstr "\"post-rewrite hook\" umgehen"
@@ -6875,44 +6889,42 @@ msgstr "Refmap"
 
 #: builtin/fetch.c:131 builtin/pull.c:211
 msgid "specify fetch refmap"
 msgstr "Refmap für 'fetch' angeben"
 
 #: builtin/fetch.c:387
 msgid "Couldn't find remote ref HEAD"
 msgstr "Konnte Remote-Referenz von HEAD nicht finden."
 
 #: builtin/fetch.c:503
 #, c-format
 msgid "configuration fetch.output contains invalid value %s"
-msgstr ""
+msgstr "Konfiguration fetch.output enthält ungültigen Wert %s"
 
 #: builtin/fetch.c:592
 #, c-format
 msgid "object %s not found"
 msgstr "Objekt %s nicht gefunden"
 
 #: builtin/fetch.c:596
 msgid "[up to date]"
 msgstr "[aktuell]"
 
 #: builtin/fetch.c:609 builtin/fetch.c:689
 msgid "[rejected]"
 msgstr "[zurückgewiesen]"
 
 #: builtin/fetch.c:610
-#, fuzzy
 msgid "can't fetch in current branch"
-msgstr ""
-"! %-*s %-*s -> %s  (kann \"fetch\" im aktuellen Branch nicht ausführen)"
+msgstr "kann \"fetch\" im aktuellen Branch nicht ausführen"
 
 #: builtin/fetch.c:619
 msgid "[tag update]"
 msgstr "[Tag Aktualisierung]"
 
 #: builtin/fetch.c:620 builtin/fetch.c:653 builtin/fetch.c:669
 #: builtin/fetch.c:684
 msgid "unable to update local ref"
 msgstr "kann lokale Referenz nicht aktualisieren"
 
 #: builtin/fetch.c:639
 msgid "[new tag]"
@@ -6922,27 +6934,26 @@ msgstr "[neues Tag]"
 msgid "[new branch]"
 msgstr "[neuer Branch]"
 
 #: builtin/fetch.c:645
 msgid "[new ref]"
 msgstr "[neue Referenz]"
 
 #: builtin/fetch.c:684
 msgid "forced update"
 msgstr "Aktualisierung erzwungen"
 
 #: builtin/fetch.c:689
-#, fuzzy
 msgid "non-fast-forward"
-msgstr "(kein Vorspulen)"
+msgstr "kein Vorspulen"
 
 #: builtin/fetch.c:733
 #, c-format
 msgid "%s did not send all necessary objects\n"
 msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
 
 #: builtin/fetch.c:753
 #, c-format
 msgid "reject %s because shallow roots are not allowed to be updated"
 msgstr ""
 "%s wurde zurückgewiesen, da Ursprungs-Commits von Repositoriesmit "
 "unvollständiger Historie (shallow) nicht aktualisiert werden dürfen."
@@ -7181,27 +7192,26 @@ msgstr "nur Konnektivität prüfen"
 msgid "enable more strict checking"
 msgstr "genauere Prüfung aktivieren"
 
 #: builtin/fsck.c:604
 msgid "write dangling objects in .git/lost-found"
 msgstr "unreferenzierte Objekte nach .git/lost-found schreiben"
 
 #: builtin/fsck.c:605 builtin/prune.c:107
 msgid "show progress"
 msgstr "Fortschrittsanzeige anzeigen"
 
 #: builtin/fsck.c:606
-#, fuzzy
 msgid "show verbose names for reachable objects"
-msgstr "unerreichbare Objekte anzeigen"
+msgstr "ausführliche Namen für erreichbare Objekte anzeigen"
 
 #: builtin/fsck.c:671
 msgid "Checking objects"
 msgstr "Prüfe Objekte"
 
 #: builtin/gc.c:25
 msgid "git gc [<options>]"
 msgstr "git gc [<Optionen>]"
 
 #: builtin/gc.c:72
 #, c-format
 msgid "Invalid %s: '%s'"
@@ -7748,27 +7758,27 @@ msgid "cannot open packfile '%s'"
 msgstr "Kann Paketdatei '%s' nicht öffnen"
 
 #: builtin/index-pack.c:333
 msgid "pack signature mismatch"
 msgstr "Paketsignatur stimmt nicht überein"
 
 #: builtin/index-pack.c:335
 #, c-format
 msgid "pack version %<PRIu32> unsupported"
 msgstr "Paketversion %<PRIu32> nicht unterstützt"
 
 #: builtin/index-pack.c:353
-#, fuzzy, c-format
+#, c-format
 msgid "pack has bad object at offset %<PRIuMAX>: %s"
-msgstr "Paket hat ein ungültiges Objekt bei Versatz %lu: %s"
+msgstr "Paket hat ein ungültiges Objekt bei Versatz %<PRIuMAX>: %s"
 
 #: builtin/index-pack.c:475
 #, c-format
 msgid "inflate returned %d"
 msgstr "Dekomprimierung gab %d zurück"
 
 #: builtin/index-pack.c:524
 msgid "offset value overflow for delta base object"
 msgstr "Wert für Versatz bei Differenzobjekt übergelaufen"
 
 #: builtin/index-pack.c:532
 msgid "delta base offset is out of bound"
@@ -7776,29 +7786,29 @@ msgstr ""
 "Wert für Versatz bei Differenzobjekt liegt außerhalb des gültigen Bereichs"
 
 #: builtin/index-pack.c:540
 #, c-format
 msgid "unknown object type %d"
 msgstr "Unbekannter Objekt-Typ %d"
 
 #: builtin/index-pack.c:571
 msgid "cannot pread pack file"
 msgstr "Kann Paketdatei %s nicht lesen"
 
 #: builtin/index-pack.c:573
-#, fuzzy, c-format
+#, c-format
 msgid "premature end of pack file, %<PRIuMAX> byte missing"
 msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
-msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %lu Byte"
-msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %lu Bytes"
+msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %<PRIuMAX> Byte"
+msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %<PRIuMAX> Bytes"
 
 #: builtin/index-pack.c:599
 msgid "serious inflate inconsistency"
 msgstr "ernsthafte Inkonsistenz nach Dekomprimierung"
 
 #: builtin/index-pack.c:745 builtin/index-pack.c:751 builtin/index-pack.c:774
 #: builtin/index-pack.c:808 builtin/index-pack.c:817
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !"
 
 #: builtin/index-pack.c:748 builtin/pack-objects.c:164
@@ -8028,42 +8038,42 @@ msgstr "%s existiert bereits"
 
 #: builtin/init-db.c:344
 #, c-format
 msgid "unable to handle file type %d"
 msgstr "kann nicht mit Dateityp %d umgehen"
 
 #: builtin/init-db.c:347
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "Konnte %s nicht nach %s verschieben"
 
 #: builtin/init-db.c:402
-#, fuzzy, c-format
+#, c-format
 msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Bestehendes verteiltes Git-Repository in %s%s neuinitialisiert\n"
 
 #: builtin/init-db.c:403
-#, fuzzy, c-format
+#, c-format
 msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Bestehendes Git-Repository in %s%s neuinitialisiert\n"
 
 #: builtin/init-db.c:407
-#, fuzzy, c-format
+#, c-format
 msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Leeres verteiltes Git-Repository in %s%s initialisiert\n"
 
 #: builtin/init-db.c:408
-#, fuzzy, c-format
+#, c-format
 msgid "Initialized empty Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Leeres Git-Repository in %s%s initialisiert\n"
 
 #: builtin/init-db.c:455
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>] [--"
 "shared[=<permissions>]] [<directory>]"
 msgstr ""
 "git init [-q | --quiet] [--bare] [--template=<Vorlagenverzeichnis>] [--"
 "shared[=<Berechtigungen>]] [<Verzeichnis>]"
 
 #: builtin/init-db.c:478
 msgid "permissions"
 msgstr "Berechtigungen"
@@ -8862,40 +8872,39 @@ msgstr "Kein Remote-Repository für den aktuellen Branch."
 msgid "No default upstream defined for the current branch."
 msgstr ""
 "Es ist kein Standard-Upstream-Branch für den aktuellen Branch definiert."
 
 #: builtin/merge.c:913
 #, c-format
 msgid "No remote-tracking branch for %s from %s"
 msgstr "Kein Remote-Tracking-Branch für %s von %s"
 
 #: builtin/merge.c:960
 #, c-format
 msgid "Bad value '%s' in environment '%s'"
-msgstr ""
+msgstr "Fehlerhafter Wert '%s' in Umgebungsvariable '%s'"
 
 #: builtin/merge.c:1034
 #, c-format
 msgid "could not close '%s'"
 msgstr "Konnte '%s' nicht schließen"
 
 #: builtin/merge.c:1061
-#, fuzzy, c-format
+#, c-format
 msgid "not something we can merge in %s: %s"
-msgstr "%s - nichts was wir zusammenführen können"
+msgstr "nichts was wir in %s zusammenführen können: %s"
 
 #: builtin/merge.c:1095
-#, fuzzy
 msgid "not something we can merge"
-msgstr "%s - nichts was wir zusammenführen können"
+msgstr "nichts was wir zusammenführen können"
 
 #: builtin/merge.c:1162
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "Es gibt keinen Merge zum Abbrechen (MERGE_HEAD fehlt)"
 
 #: builtin/merge.c:1178
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you merge."
 msgstr ""
 "Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert).\n"
 "Bitte committen Sie Ihre Änderungen, bevor Sie den Merge ausführen."
@@ -8958,47 +8967,45 @@ msgid "Commit %s does not have a GPG signature."
 msgstr "Commit %s hat keine GPG-Signatur."
 
 #: builtin/merge.c:1296
 #, c-format
 msgid "Commit %s has a good GPG signature by %s\n"
 msgstr "Commit %s hat eine gültige GPG-Signatur von %s\n"
 
 #: builtin/merge.c:1358
 msgid "refusing to merge unrelated histories"
 msgstr "Verweigere den Merge von nicht zusammenhängenden Historien."
 
 #: builtin/merge.c:1367
-#, fuzzy
 msgid "Already up-to-date."
-msgstr "Bereits aktuell!"
+msgstr "Bereits aktuell."
 
 #: builtin/merge.c:1382
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Aktualisiere %s..%s\n"
 
 #: builtin/merge.c:1419
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Probiere wirklich trivialen \"in-index\"-Merge ...\n"
 
 #: builtin/merge.c:1426
 #, c-format
 msgid "Nope.\n"
 msgstr "Nein.\n"
 
 #: builtin/merge.c:1451
-#, fuzzy
 msgid "Already up-to-date. Yeeah!"
-msgstr "Bereits aktuell!"
+msgstr "Bereits aktuell."
 
 #: builtin/merge.c:1457
 msgid "Not possible to fast-forward, aborting."
 msgstr "Vorspulen nicht möglich, breche ab."
 
 #: builtin/merge.c:1480 builtin/merge.c:1559
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Rücklauf des Verzeichnisses bis zum Ursprung ...\n"
 
 #: builtin/merge.c:1484
 #, c-format
@@ -9362,25 +9369,25 @@ msgid "git notes remove [<object>]"
 msgstr "git notes remove [<Objekt>]"
 
 #: builtin/notes.c:84
 msgid "git notes prune [<options>]"
 msgstr "git notes prune [<Optionen>]"
 
 #: builtin/notes.c:89
 msgid "git notes get-ref"
 msgstr "git notes get-ref"
 
 #: builtin/notes.c:94
 msgid "Write/edit the notes for the following object:"
-msgstr ""
+msgstr "Schreiben/Bearbeiten der Notizen für das folgende Objekt:"
 
 #: builtin/notes.c:147
 #, c-format
 msgid "unable to start 'show' for object '%s'"
 msgstr "konnte 'show' für Objekt '%s' nicht starten"
 
 #: builtin/notes.c:151
 msgid "could not read 'show' output"
 msgstr "Konnte Ausgabe von 'show' nicht lesen."
 
 #: builtin/notes.c:159
 #, c-format
@@ -9504,27 +9511,27 @@ msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Keine Notizen für Quell-Objekt %s. Kopie nicht möglich."
 
 #: builtin/notes.c:587
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
 "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
 msgstr ""
 "Die Optionen -m/-F/-c/-C sind für den Unterbefehl 'edit' veraltet.\n"
 "Bitte benutzen Sie stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
 
 #: builtin/notes.c:753
-#, fuzzy, c-format
+#, c-format
 msgid "unknown notes merge strategy %s"
-msgstr "Konnte Merge-Strategie '%s' nicht finden.\n"
+msgstr "unbekannte Merge-Strategie '%s' für Notizen"
 
 #: builtin/notes.c:769
 msgid "General options"
 msgstr "Allgemeine Optionen"
 
 #: builtin/notes.c:771
 msgid "Merge options"
 msgstr "Merge-Optionen"
 
 #: builtin/notes.c:773
 msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
@@ -9544,75 +9551,76 @@ msgstr ""
 "committet werden"
 
 #: builtin/notes.c:779
 msgid "Aborting notes merge resolution"
 msgstr "Konfliktauflösung beim Merge von Notizen abbrechen"
 
 #: builtin/notes.c:781
 msgid "abort notes merge"
 msgstr "Merge von Notizen abbrechen"
 
 #: builtin/notes.c:792
 msgid "cannot mix --commit, --abort or -s/--strategy"
-msgstr ""
+msgstr "Kann --commit, --abort oder -s/--strategy nicht kombinieren."
 
 #: builtin/notes.c:797
-#, fuzzy
 msgid "Must specify a notes ref to merge"
-msgstr "Sie müssen ein Repository angeben."
+msgstr "Sie müssen eine Notiz-Referenz zum Mergen angeben."
 
 #: builtin/notes.c:821
-#, fuzzy, c-format
+#, c-format
 msgid "Unknown -s/--strategy: %s"
-msgstr "Unbekannter Typ: %d"
+msgstr "Unbekannter Wert für -s/--strategy: %s"
 
 #: builtin/notes.c:858
 #, c-format
 msgid "A notes merge into %s is already in-progress at %s"
 msgstr "Ein Merge von Notizen nach %s ist bereits im Gange bei %s"
 
 #: builtin/notes.c:861
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to store link to current notes ref (%s)"
-msgstr "Fehler beim Finden des \"Tree\"-Objektes von %s."
+msgstr "Fehler beim Speichern der Verknüpfung zur aktuellen Notes-Referenz (%s)"
 
 #: builtin/notes.c:863
 #, c-format
 msgid ""
 "Automatic notes merge failed. Fix conflicts in %s and commit the result with "
 "'git notes merge --commit', or abort the merge with 'git notes merge --"
 "abort'.\n"
 msgstr ""
+"Automatisches Zusammenführen der Notizen fehlgeschlagen. Beheben Sie die\n"
+"Konflikte in %s und committen Sie das Ergebnis mit 'git notes merge --commit',\n"
+"oder brechen Sie den Merge mit 'git notes merge --abort' ab.\n"
 
 #: builtin/notes.c:885
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Objekt %s hat keine Notiz\n"
 
 #: builtin/notes.c:897
 msgid "attempt to remove non-existent note is not an error"
 msgstr "der Versuch, eine nicht existierende Notiz zu löschen, ist kein Fehler"
 
 #: builtin/notes.c:900
 msgid "read object names from the standard input"
 msgstr "Objektnamen von der Standard-Eingabe lesen"
 
 #: builtin/notes.c:938 builtin/prune.c:105 builtin/worktree.c:127
 msgid "do not remove, show only"
 msgstr "nicht löschen, nur anzeigen"
 
 #: builtin/notes.c:939
-#, fuzzy
 msgid "report pruned notes"
-msgstr "gelöschte Objekte melden"
+msgstr "gelöschte Notizen melden"
 
 #: builtin/notes.c:981
 msgid "notes-ref"
 msgstr "Notiz-Referenz"
 
 #: builtin/notes.c:982
 msgid "use notes from <notes-ref>"
 msgstr "Notizen von <Notiz-Referenz> verwenden"
 
 #: builtin/notes.c:1017 builtin/remote.c:1623
 #, c-format
 msgid "Unknown subcommand: %s"
@@ -9767,27 +9775,26 @@ msgstr "Objekte einschließen, die vom Index referenziert werden"
 msgid "output pack to stdout"
 msgstr "Paket in die Standard-Ausgabe schreiben"
 
 #: builtin/pack-objects.c:2695
 msgid "include tag objects that refer to objects to be packed"
 msgstr "Tag-Objekte einschließen, die auf gepackte Objekte referenzieren"
 
 #: builtin/pack-objects.c:2697
 msgid "keep unreachable objects"
 msgstr "nicht erreichbare Objekte behalten"
 
 #: builtin/pack-objects.c:2699
-#, fuzzy
 msgid "pack loose unreachable objects"
-msgstr "nicht erreichbare Objekte behalten"
+msgstr "nicht erreichbare lose Objekte packen"
 
 #: builtin/pack-objects.c:2700 parse-options.h:142
 msgid "time"
 msgstr "Zeit"
 
 #: builtin/pack-objects.c:2701
 msgid "unpack unreachable objects newer than <time>"
 msgstr "nicht erreichbare Objekte entpacken, die neuer als <Zeit> sind"
 
 #: builtin/pack-objects.c:2704
 msgid "create thin packs"
 msgstr "dünnere Pakete erzeugen"
@@ -9985,25 +9992,25 @@ msgstr ""
 #: builtin/pull.c:503
 #, c-format
 msgid ""
 "Your configuration specifies to merge with the ref '%s'\n"
 "from the remote, but no such ref was fetched."
 msgstr ""
 "Ihre Konfiguration gibt an, den Merge mit Referenz '%s'\n"
 "des Remote-Repositories durchzuführen, aber diese Referenz\n"
 "wurde nicht angefordert."
 
 #: builtin/pull.c:820
 msgid "ignoring --verify-signatures for rebase"
-msgstr ""
+msgstr "Ignoriere --verify-signatures für Rebase"
 
 #: builtin/pull.c:867
 msgid "--[no-]autostash option is only valid with --rebase."
 msgstr "--[no-]autostash ist nur mit --rebase zulässig."
 
 #: builtin/pull.c:875
 msgid "Updating an unborn branch with changes added to the index."
 msgstr ""
 "Aktualisiere einen ungeborenen Branch mit Änderungen, die zum Commit "
 "vorgemerkt sind."
 
 #: builtin/pull.c:903
@@ -10323,42 +10330,41 @@ msgid "push missing but relevant tags"
 msgstr "fehlende, aber relevante Tags versenden"
 
 #: builtin/push.c:543 builtin/send-pack.c:166
 msgid "GPG sign the push"
 msgstr "signiert \"push\" mit GPG"
 
 #: builtin/push.c:545 builtin/send-pack.c:170
 msgid "request atomic transaction on remote side"
 msgstr "Referenzen atomar versenden"
 
 #: builtin/push.c:546
 msgid "server-specific"
-msgstr ""
+msgstr "serverspezifisch"
 
 #: builtin/push.c:546
-#, fuzzy
 msgid "option to transmit"
-msgstr "nichts zu committen\n"
+msgstr "Option übertragen"
 
 #: builtin/push.c:560
 msgid "--delete is incompatible with --all, --mirror and --tags"
 msgstr "Die Option --delete ist inkompatibel mit --all, --mirror und --tags."
 
 #: builtin/push.c:562
 msgid "--delete doesn't make sense without any refs"
 msgstr "Die Option --delete kann nur mit Referenzen verwendet werden."
 
 #: builtin/push.c:579
 msgid "push options must not have new line characters"
-msgstr ""
+msgstr "Push-Optionen dürfen keine Zeilenvorschubzeichen haben"
 
 #: builtin/read-tree.c:37
 msgid ""
 "git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) "
 "[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
 "index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
 msgstr ""
 "git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<Präfix>) "
 "[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
 "index-output=<Datei>] (--empty | <Commit-Referenz1> [<Commit-Referenz2> "
 "[<Commit-Referenz3>]])"
 
@@ -10689,42 +10695,42 @@ msgstr " ???"
 
 #: builtin/remote.c:955
 #, c-format
 msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
 msgstr "ungültiges branch.%s.merge; kann Rebase nicht auf > 1 Branch ausführen"
 
 #: builtin/remote.c:963
 #, c-format
 msgid "rebases interactively onto remote %s"
 msgstr "interaktiver Rebase auf Remote-Branch %s"
 
 #: builtin/remote.c:964
-#, fuzzy, c-format
+#, c-format
 msgid "rebases onto remote %s"
-msgstr "interaktiver Rebase auf Remote-Branch %s"
+msgstr "Rebase auf Remote-Branch %s"
 
 #: builtin/remote.c:967
 #, c-format
 msgid " merges with remote %s"
 msgstr " führt mit Remote-Branch %s zusammen"
 
 #: builtin/remote.c:970
 #, c-format
 msgid "merges with remote %s"
 msgstr "führt mit Remote-Branch %s zusammen"
 
 #: builtin/remote.c:973
-#, fuzzy, c-format
+#, c-format
 msgid "%-*s    and with remote %s\n"
-msgstr "    und mit Remote-Branch"
+msgstr "%-*s    und mit Remote-Branch %s\n"
 
 #: builtin/remote.c:1016
 msgid "create"
 msgstr "erstellt"
 
 #: builtin/remote.c:1019
 msgid "delete"
 msgstr "gelöscht"
 
 #: builtin/remote.c:1023
 msgid "up to date"
 msgstr "aktuell"
@@ -10779,32 +10785,30 @@ msgstr "(keine URL)"
 #. the one in "  Fetch URL: %s" translation
 #: builtin/remote.c:1154 builtin/remote.c:1156
 #, c-format
 msgid "  Push  URL: %s"
 msgstr "  URL zum Versenden: %s"
 
 #: builtin/remote.c:1158 builtin/remote.c:1160 builtin/remote.c:1162
 #, c-format
 msgid "  HEAD branch: %s"
 msgstr "  Hauptbranch: %s"
 
 #: builtin/remote.c:1158
-#, fuzzy
 msgid "(not queried)"
-msgstr " (Zustand nicht abgefragt)"
+msgstr "(nicht abgefragt)"
 
 #: builtin/remote.c:1160
-#, fuzzy
 msgid "(unknown)"
-msgstr "unbekannt:"
+msgstr "(unbekannt)"
 
 #: builtin/remote.c:1164
 #, c-format
 msgid ""
 "  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
 msgstr ""
 "  Hauptbranch (externer HEAD ist mehrdeutig, könnte einer der folgenden "
 "sein):\n"
 
 #: builtin/remote.c:1176
 #, c-format
 msgid "  Remote branch:%s"
@@ -10997,27 +11001,26 @@ msgstr "--local an git-pack-objects übergeben"
 msgid "write bitmap index"
 msgstr "Bitmap-Index schreiben"
 
 #: builtin/repack.c:177
 msgid "approxidate"
 msgstr "Datumsangabe"
 
 #: builtin/repack.c:178
 msgid "with -A, do not loosen objects older than this"
 msgstr "mit -A, keine Objekte älter als dieses Datum löschen"
 
 #: builtin/repack.c:180
-#, fuzzy
 msgid "with -a, repack unreachable objects"
-msgstr "nicht erreichbare Objekte behalten"
+msgstr "mit -a, nicht erreichbare Objekte neu packen"
 
 #: builtin/repack.c:182
 msgid "size of the window used for delta compression"
 msgstr "Größe des Fensters für die Delta-Kompression"
 
 #: builtin/repack.c:183 builtin/repack.c:187
 msgid "bytes"
 msgstr "Bytes"
 
 #: builtin/repack.c:184
 msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
@@ -11033,27 +11036,26 @@ msgid "maximum size of each packfile"
 msgstr "maximale Größe für jede Paketdatei"
 
 #: builtin/repack.c:190
 msgid "repack objects in packs marked with .keep"
 msgstr ""
 "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
 
 #: builtin/repack.c:200
 msgid "cannot delete packs in a precious-objects repo"
 msgstr "kann Pack-Dateien in precious-objects Repository nicht löschen"
 
 #: builtin/repack.c:204
-#, fuzzy
 msgid "--keep-unreachable and -A are incompatible"
-msgstr "--column und -n sind inkompatibel"
+msgstr "--keep-unreachable und -A sind inkompatibel"
 
 #: builtin/repack.c:391 builtin/worktree.c:115
 #, c-format
 msgid "failed to remove '%s'"
 msgstr "Fehler beim Löschen von '%s'"
 
 #: builtin/replace.c:19
 msgid "git replace [-f] <object> <replacement>"
 msgstr "git replace [-f] <Objekt> <Ersetzung>"
 
 #: builtin/replace.c:20
 msgid "git replace [-f] --edit <object>"
@@ -11821,32 +11823,32 @@ msgstr "Meinten Sie vielleicht 'update --init'?"
 
 #: builtin/submodule--helper.c:641
 #, c-format
 msgid "Skipping unmerged submodule %s"
 msgstr "Überspringe nicht zusammengeführtes Submodul %s"
 
 #: builtin/submodule--helper.c:662
 #, c-format
 msgid "Skipping submodule '%s'"
 msgstr "Überspringe Submodul '%s'"
 
 #: builtin/submodule--helper.c:792
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
-msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
+msgstr "Fehler beim Klonen von '%s'. Weiterer Versuch geplant"
 
 #: builtin/submodule--helper.c:803
 #, c-format
 msgid "Failed to clone '%s' a second time, aborting"
-msgstr ""
+msgstr "Zweiter Versuch '%s' zu klonen fehlgeschlagen, breche ab."
 
 #: builtin/submodule--helper.c:824
 msgid "path into the working tree"
 msgstr "Pfad zum Arbeitsverzeichnis"
 
 #: builtin/submodule--helper.c:827
 msgid "path into the working tree, across nested submodule boundaries"
 msgstr ""
 "Pfad zum Arbeitsverzeichnis, über verschachtelte Submodul-Grenzen hinweg"
 
 #: builtin/submodule--helper.c:831
 msgid "rebase, merge, checkout or none"
@@ -11857,43 +11859,47 @@ msgid "Create a shallow clone truncated to the specified number of revisions"
 msgstr ""
 "Erstellung eines Klons mit unvollständiger Historie (shallow), abgeschnitten "
 "bei\n"
 "der angegebenen Anzahl von Commits."
 
 #: builtin/submodule--helper.c:838
 msgid "parallel jobs"
 msgstr "Parallele Ausführungen"
 
 #: builtin/submodule--helper.c:840
 msgid "whether the initial clone should follow the shallow recommendation"
 msgstr ""
+"ob das initiale Klonen den Empfehlungen für eine unvollständige\n"
+"Historie (shallow) folgen soll"
 
 #: builtin/submodule--helper.c:841
 msgid "don't print cloning progress"
 msgstr "keine Fortschrittsanzeige beim Klonen"
 
 #: builtin/submodule--helper.c:846
 msgid "git submodule--helper update_clone [--prefix=<path>] [<path>...]"
 msgstr "git submodule--helper update_clone [--prefix=<Pfad>] [<Pfad>...]"
 
 #: builtin/submodule--helper.c:856
 msgid "bad value for update parameter"
 msgstr "Fehlerhafter Wert für --update Parameter"
 
 #: builtin/submodule--helper.c:927
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
 "the superproject is not on any branch"
 msgstr ""
+"Branch von Submodul (%s) ist konfiguriert, den Branch des Hauptprojektes\n"
+"zu erben, aber das Hauptprojekt befindet sich auf keinem Branch."
 
 #: builtin/submodule--helper.c:977
 msgid "submodule--helper subcommand must be called with a subcommand"
 msgstr "submodule--helper muss mit einem Unterbefehl aufgerufen werden"
 
 #: builtin/submodule--helper.c:984
 #, c-format
 msgid "'%s' is not a valid submodule--helper subcommand"
 msgstr "'%s' ist kein gültiger Unterbefehl von submodule--helper"
 
 #: builtin/symbolic-ref.c:7
 msgid "git symbolic-ref [<options>] <name> [<ref>]"
@@ -12406,36 +12412,34 @@ msgstr "git verify-tag [-v | --verbose] <Tag>..."
 msgid "print tag contents"
 msgstr "Tag-Inhalte ausgeben"
 
 #: builtin/worktree.c:15
 msgid "git worktree add [<options>] <path> [<branch>]"
 msgstr "git worktree add [<Optionen>] <Pfad> [<Branch>]"
 
 #: builtin/worktree.c:16
 msgid "git worktree list [<options>]"
 msgstr "git worktree list [<Optionen>]"
 
 #: builtin/worktree.c:17
-#, fuzzy
 msgid "git worktree lock [<options>] <path>"
-msgstr "git worktree list [<Optionen>]"
+msgstr "git worktree lock [<Optionen>] <Pfad>"
 
 #: builtin/worktree.c:18
 msgid "git worktree prune [<options>]"
 msgstr "git worktree prune [<Optionen>]"
 
 #: builtin/worktree.c:19
-#, fuzzy
 msgid "git worktree unlock <path>"
-msgstr "git worktree prune [<Optionen>]"
+msgstr "git worktree unlock <Pfad>"
 
 #: builtin/worktree.c:42
 #, c-format
 msgid "Removing worktrees/%s: not a valid directory"
 msgstr "Lösche worktrees/%s: kein gültiges Verzeichnis"
 
 #: builtin/worktree.c:48
 #, c-format
 msgid "Removing worktrees/%s: gitdir file does not exist"
 msgstr "Lösche worktrees/%s: gitdir-Datei existiert nicht"
 
 #: builtin/worktree.c:53
@@ -12483,86 +12487,85 @@ msgid "create or reset a branch"
 msgstr "Branch erstellen oder umsetzen"
 
 #: builtin/worktree.c:329
 msgid "populate the new working tree"
 msgstr "das neue Arbeitsverzeichnis auschecken"
 
 #: builtin/worktree.c:337
 msgid "-b, -B, and --detach are mutually exclusive"
 msgstr "-b, -B und --detach schließen sich gegenseitig aus"
 
 #: builtin/worktree.c:470
 msgid "reason for locking"
-msgstr ""
+msgstr "Sperrgrund"
 
 #: builtin/worktree.c:482 builtin/worktree.c:515
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is not a working tree"
-msgstr "'%s' ist kein Commit"
+msgstr "'%s' ist kein Arbeitsverzeichnis"
 
 #: builtin/worktree.c:484 builtin/worktree.c:517
 msgid "The main working tree cannot be locked or unlocked"
-msgstr ""
+msgstr "Das Hauptarbeitsverzeichnis kann nicht gesperrt oder entsperrt werden."
 
 #: builtin/worktree.c:489
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is already locked, reason: %s"
-msgstr "'%s' ist bereits in '%s' ausgecheckt"
+msgstr "'%s' ist bereits gesperrt, Grund: %s"
 
 #: builtin/worktree.c:491
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is already locked"
-msgstr "'%s' ist bereits in '%s' ausgecheckt"
+msgstr "'%s' ist bereits gesperrt"
 
 #: builtin/worktree.c:519
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is not locked"
-msgstr "'%s' ist kein Commit"
+msgstr "'%s' ist nicht gesperrt"
 
 #: builtin/write-tree.c:13
 msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
 msgstr "git write-tree [--missing-ok] [--prefix=<Präfix>/]"
 
 #: builtin/write-tree.c:26
 msgid "<prefix>/"
 msgstr "<Präfix>/"
 
 #: builtin/write-tree.c:27
 msgid "write tree object for a subdirectory <prefix>"
 msgstr "das \"Tree\"-Objekt für ein Unterverzeichnis <Präfix> schreiben"
 
 #: builtin/write-tree.c:30
 msgid "only useful for debugging"
 msgstr "nur nützlich für Fehlersuche"
 
 #: upload-pack.c:20
-#, fuzzy
 msgid "git upload-pack [<options>] <dir>"
-msgstr "git repack [<Optionen>]"
+msgstr "git upload-pack [<Optionen>] <Verzeichnis>"
 
 #: upload-pack.c:837
 msgid "quit after a single request/response exchange"
-msgstr ""
+msgstr "nach einem einzigen Request/Response-Austausch beenden"
 
 #: upload-pack.c:839
 msgid "exit immediately after initial ref advertisement"
-msgstr ""
+msgstr "direkt nach der initialen Angabe der Commits beenden"
 
 #: upload-pack.c:841
 msgid "do not try <directory>/.git/ if <directory> is no Git directory"
-msgstr ""
+msgstr "kein Versuch in <Verzeichnis>/.git/ wenn <Verzeichnis> kein Git-Verzeichnis ist"
 
 #: upload-pack.c:843
 msgid "interrupt transfer after <n> seconds of inactivity"
-msgstr ""
+msgstr "Übertragung nach <n> Sekunden Inaktivität unterbrechen"
 
 #: credential-cache--daemon.c:271
 msgid "print debugging messages to stderr"
 msgstr "Meldungen zur Fehlersuche in Standard-Fehlerausgabe ausgeben"
 
 #: git.c:14
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
 "concept guides. See 'git help <command>' or 'git help <concept>'\n"
 "to read about a specific subcommand or concept."
 msgstr ""
 "'git help -a' und 'git help -g' listet verfügbare Unterbefehle und\n"
@@ -12759,27 +12762,27 @@ msgstr "Ungültiger HEAD - merkwürdige symbolische Referenz"
 
 #: git-bisect.sh:233
 #, sh-format
 msgid "Bad bisect_write argument: $state"
 msgstr "Ungültiges \"bisect_write\" Argument: $state"
 
 #: git-bisect.sh:262
 #, sh-format
 msgid "Bad rev input: $arg"
 msgstr "Ungültige Referenz-Eingabe: $arg"
 
 #: git-bisect.sh:281
-#, fuzzy, sh-format
+#, sh-format
 msgid "Bad rev input: $bisected_head"
-msgstr "Ungültige Referenz-Eingabe: $arg"
+msgstr "Ungültige Referenz-Eingabe: $bisected_head"
 
 #: git-bisect.sh:290
 #, sh-format
 msgid "Bad rev input: $rev"
 msgstr "Ungültige Referenz-Eingabe: $rev"
 
 #: git-bisect.sh:299
 #, sh-format
 msgid "'git bisect $TERM_BAD' can take only one argument."
 msgstr "'git bisect $TERM_BAD' kann nur ein Argument entgegennehmen."
 
 #: git-bisect.sh:322
@@ -12911,65 +12914,62 @@ msgid "no terms defined"
 msgstr "Keine Begriffe definiert."
 
 #: git-bisect.sh:653
 #, sh-format
 msgid ""
 "invalid argument $arg for 'git bisect terms'.\n"
 "Supported options are: --term-good|--term-old and --term-bad|--term-new."
 msgstr ""
 "Ungültiges Argument $arg für 'git bisect terms'.\n"
 "Unterstützte Optionen sind: --term-good|--term-old und --term-bad|--term-new."
 
 #: git-merge-octopus.sh:46
-#, fuzzy
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
 msgstr ""
-"Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
-"überschrieben werden:\n"
-"%%s"
+"Fehler Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
+"überschrieben werden"
 
 #: git-merge-octopus.sh:61
 msgid "Automated merge did not work."
-msgstr ""
+msgstr "Automatischer Merge hat nicht funktioniert."
 
 #: git-merge-octopus.sh:62
-#, fuzzy
 msgid "Should not be doing an Octopus."
-msgstr "Konnte Ausgabe nicht umleiten."
+msgstr "Sollte keinen Octopus-Merge ausführen."
 
 #: git-merge-octopus.sh:73
 #, sh-format
 msgid "Unable to find common commit with $pretty_name"
-msgstr ""
+msgstr "Konnte keinen gemeinsamen Commit mit $pretty_name finden."
 
 #: git-merge-octopus.sh:77
-#, fuzzy, sh-format
+#, sh-format
 msgid "Already up-to-date with $pretty_name"
-msgstr "Bereits aktuell!"
+msgstr "Bereits aktuell mit $pretty_name"
 
 #: git-merge-octopus.sh:89
-#, fuzzy, sh-format
+#, sh-format
 msgid "Fast-forwarding to: $pretty_name"
-msgstr "$branch_name zu $onto_name vorgespult."
+msgstr "Spule vor zu: $pretty_name"
 
 #: git-merge-octopus.sh:97
 #, sh-format
 msgid "Trying simple merge with $pretty_name"
-msgstr ""
+msgstr "Versuche einfachen Merge mit $pretty_name"
 
 #: git-merge-octopus.sh:102
 msgid "Simple merge did not work, trying automatic merge."
-msgstr ""
+msgstr "Einfacher Merge hat nicht funktioniert, versuche automatischen Merge."
 
 #: git-rebase.sh:56
 msgid ""
 "When you have resolved this problem, run \"git rebase --continue\".\n"
 "If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
 "To check out the original branch and stop rebasing, run \"git rebase --abort"
 "\"."
 msgstr ""
 "Wenn Sie das Problem aufgelöst haben, führen Sie \"git rebase --continue\" "
 "aus.\n"
 "Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"git "
 "rebase --skip\" aus.\n"
@@ -13175,25 +13175,25 @@ msgstr "Keine lokalen Änderungen zum Speichern"
 
 #: git-stash.sh:263
 msgid "Cannot initialize stash"
 msgstr "Kann \"stash\" nicht initialisieren"
 
 #: git-stash.sh:267
 msgid "Cannot save the current status"
 msgstr "Kann den aktuellen Status nicht speichern"
 
 #: git-stash.sh:268
 #, sh-format
 msgid "Saved working directory and index state $stash_msg"
-msgstr ""
+msgstr "Speicherte Arbeitsverzeichnis und Index-Status $stash_msg"
 
 #: git-stash.sh:285
 msgid "Cannot remove worktree changes"
 msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
 
 #: git-stash.sh:404
 #, sh-format
 msgid "unknown option: $opt"
 msgstr "unbekannte Option: $opt"
 
 #: git-stash.sh:414
 msgid "No stash found."
@@ -13236,25 +13236,25 @@ msgid "Could not save index tree"
 msgstr "Konnte Index-Verzeichnis nicht speichern"
 
 #: git-stash.sh:522
 msgid "Cannot unstage modified files"
 msgstr "Kann geänderte Dateien nicht aus dem Index entfernen"
 
 #: git-stash.sh:537
 msgid "Index was not unstashed."
 msgstr "Index wurde nicht aus dem Stash zurückgeladen."
 
 #: git-stash.sh:551
 msgid "The stash is kept in case you need it again."
-msgstr ""
+msgstr "Der Stash wird behalten, im Falle Sie benötigen diesen nochmal."
 
 #: git-stash.sh:560
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Gelöscht ${REV} ($s)"
 
 #: git-stash.sh:561
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen"
 
 #: git-stash.sh:569
@@ -13310,24 +13310,29 @@ msgstr ""
 "Repositories:"
 
 #: git-submodule.sh:244
 #, sh-format
 msgid ""
 "If you want to reuse this local git directory instead of cloning again from\n"
 "  $realrepo\n"
 "use the '--force' option. If the local git directory is not the correct "
 "repo\n"
 "or you are unsure what this means choose another name with the '--name' "
 "option."
 msgstr ""
+"Wenn Sie das lokale Git-Verzeichnis wiederverwenden wollen, anstatt erneut von\n"
+"  $realrepo\n"
+"zu klonen, benutzen Sie die Option '--force'. Wenn das lokale Git-Verzeichnis\n"
+"nicht das korrekte Repository ist oder Sie unsicher sind, was das bedeutet,\n"
+"wählen Sie einen anderen Namen mit der Option '--name'."
 
 #: git-submodule.sh:250
 #, sh-format
 msgid "Reactivating local git directory for submodule '$sm_name'."
 msgstr "Reaktiviere lokales Git-Verzeichnis für Submodul '$sm_name'."
 
 #: git-submodule.sh:262
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Kann Submodul '$sm_path' nicht auschecken"
 
 #: git-submodule.sh:267
@@ -13354,33 +13359,32 @@ msgstr "Stoppe bei '$displaypath'; Skript gab nicht-Null Status zurück."
 #, sh-format
 msgid "pathspec and --all are incompatible"
 msgstr "Pfadspezifikationen und --all sind inkompatibel."
 
 #: git-submodule.sh:419
 #, sh-format
 msgid "Use '--all' if you really want to deinitialize all submodules"
 msgstr ""
 "Verwenden Sie '--all', wenn Sie wirklich alle Submodule deinitialisieren\n"
 "möchten."
 
 #: git-submodule.sh:439
-#, fuzzy, sh-format
+#, sh-format
 msgid ""
 "Submodule work tree '$displaypath' contains a .git directory\n"
 "(use 'rm -rf' if you really want to remove it including all of its history)"
 msgstr ""
-"Submodul '%s' (oder ein geschachteltes Submodul hiervon) verwendet\n"
-"ein .git-Verzeichnis (benutzen Sie 'rm -rf' wenn Sie dieses wirklich "
-"mitsamt\n"
-"seiner Historie löschen möchten)"
+"Arbeitsverzeichnis von Submodul in '$displaypath' enthält ein .git-Verzeichnis\n"
+"(benutzen Sie 'rm -rf' wenn Sie dieses wirklich mitsamt seiner Historie löschen\n"
+"möchten)"
 
 #: git-submodule.sh:447
 #, sh-format
 msgid ""
 "Submodule work tree '$displaypath' contains local modifications; use '-f' to "
 "discard them"
 msgstr ""
 "Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Änderungen; "
 "verwenden Sie '-f', um diese zu verwerfen"
 
 #: git-submodule.sh:450
 #, sh-format
@@ -13408,41 +13412,45 @@ msgstr ""
 
 #: git-submodule.sh:612
 #, sh-format
 msgid "Unable to find current revision in submodule path '$displaypath'"
 msgstr "Konnte aktuellen Commit in Submodul-Pfad '$displaypath' nicht finden."
 
 #: git-submodule.sh:622
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr "Konnte \"fetch\" in Submodul-Pfad '$sm_path' nicht ausführen"
 
 #: git-submodule.sh:627
-#, fuzzy, sh-format
+#, sh-format
 msgid ""
 "Unable to find current ${remote_name}/${branch} revision in submodule path "
 "'$sm_path'"
-msgstr "Konnte aktuellen Commit in Submodul-Pfad '$displaypath' nicht finden."
+msgstr ""
+"Konnte aktuellen Commit von ${remote_name}/${branch} in Submodul-Pfad\n"
+"'$sm_path' nicht finden."
 
 #: git-submodule.sh:645
 #, sh-format
 msgid "Unable to fetch in submodule path '$displaypath'"
 msgstr "Konnte \"fetch\" in Submodul-Pfad '$displaypath' nicht ausführen"
 
 #: git-submodule.sh:651
 #, sh-format
 msgid ""
 "Fetched in submodule path '$displaypath', but it did not contain $sha1. "
 "Direct fetching of that commit failed."
 msgstr ""
+"\"fetch\" in Submodul-Pfad '$displaypath' ausgeführt, aber $sha1 nicht\n"
+"enthalten. Direktes Anfordern dieses Commits ist fehlgeschlagen."
 
 #: git-submodule.sh:658
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
 msgstr "Konnte '$sha1' in Submodul-Pfad '$displaypath' nicht auschecken."
 
 #: git-submodule.sh:659
 #, sh-format
 msgid "Submodule path '$displaypath': checked out '$sha1'"
 msgstr "Submodul-Pfad: '$displaypath': '$sha1' ausgecheckt"
 
 #: git-submodule.sh:663
@@ -13521,420 +13529,471 @@ msgstr "Fehler bei Rekursion in Submodul-Pfad '$sm_path'"
 #, sh-format
 msgid "Synchronizing submodule url for '$displaypath'"
 msgstr "Synchronisiere Submodul-URL für '$displaypath'"
 
 #: git-parse-remote.sh:89
 #, sh-format
 msgid "See git-${cmd}(1) for details."
 msgstr "Siehe git-${cmd}(1) für weitere Details."
 
 #: git-rebase--interactive.sh:131
 #, sh-format
 msgid "Rebasing ($new_count/$total)"
-msgstr ""
+msgstr "Führe Rebase aus ($new_count/$total)"
 
 #: git-rebase--interactive.sh:147
 msgid ""
 "\n"
 "Commands:\n"
 " p, pick = use commit\n"
 " r, reword = use commit, but edit the commit message\n"
 " e, edit = use commit, but stop for amending\n"
 " s, squash = use commit, but meld into previous commit\n"
 " f, fixup = like \"squash\", but discard this commit's log message\n"
 " x, exec = run command (the rest of the line) using shell\n"
 " d, drop = remove commit\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
+"\n"
+"Befehle:\n"
+" p, pick = Commit verwenden\n"
+" r, reword = Commit verwenden, aber Commit-Beschreibung bearbeiten\n"
+" e, edit = Commit verwenden, aber zum Nachbessern anhalten\n"
+" s, squash = Commit verwenden, aber mit vorherigem Commit vereinen\n"
+" f, fixup = wie \"squash\", aber diese Commit-Beschreibung verwerfen\n"
+" x, exec = Befehl (Rest der Zeile) mittels Shell ausführen\n"
+" d, drop = Commit entfernen\n"
+"\n"
+"Diese Zeilen können umsortiert werden; Sie werden von oben nach unten\n"
+"ausgeführt.\n"
 
 #: git-rebase--interactive.sh:162
 msgid ""
 "\n"
 "Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
 msgstr ""
+"\n"
+"Keine Zeile entfernen. Benutzen Sie 'drop', um explizit einen Commit zu\n"
+"entfernen.\n"
 
 #: git-rebase--interactive.sh:166
 msgid ""
 "\n"
 "If you remove a line here THAT COMMIT WILL BE LOST.\n"
-msgstr ""
+msgstr "\nWenn Sie hier eine Zeile entfernen, wird DIESER COMMIT VERLOREN GEHEN.\n"
 
 #: git-rebase--interactive.sh:202
 #, sh-format
 msgid ""
 "You can amend the commit now, with\n"
 "\n"
 "\tgit commit --amend $gpg_sign_opt_quoted\n"
 "\n"
 "Once you are satisfied with your changes, run\n"
 "\n"
 "\tgit rebase --continue"
 msgstr ""
+"Sie können den Commit nun nachbessern mit:\n"
+"\n"
+"\tgit commit --amend $gpg_sign_opt_quoted\n"
+"\n"
+"Sobald Sie mit Ihren Änderungen zufrieden sind, führen Sie aus:\n"
+"\n"
+"\tgit rebase --continue"
 
 #: git-rebase--interactive.sh:227
 #, sh-format
 msgid "$sha1: not a commit that can be picked"
-msgstr ""
+msgstr "$sha1: kein Commit der gepickt werden kann"
 
 #: git-rebase--interactive.sh:266
-#, fuzzy, sh-format
+#, sh-format
 msgid "Invalid commit name: $sha1"
-msgstr "Ungültiger Commit: %s"
+msgstr "Ungültiger Commit-Name: $sha1"
 
 #: git-rebase--interactive.sh:308
-#, fuzzy
 msgid "Cannot write current commit's replacement sha1"
-msgstr "Kann den aktuellen Zustand des Arbeitsverzeichnisses nicht speichern"
+msgstr "Kann ersetzenden SHA-1 des aktuellen Commits nicht schreiben"
 
 #: git-rebase--interactive.sh:360
-#, fuzzy, sh-format
+#, sh-format
 msgid "Fast-forward to $sha1"
-msgstr "vorspulbar"
+msgstr "Spule vor zu $sha1"
 
 #: git-rebase--interactive.sh:362
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot fast-forward to $sha1"
-msgstr "Kann $stash_sha1 nicht speichern."
+msgstr "Kann nicht zu $sha1 vorspulen"
 
 #: git-rebase--interactive.sh:371
 #, sh-format
 msgid "Cannot move HEAD to $first_parent"
-msgstr ""
+msgstr "Kann HEAD nicht auf $first_parent setzen"
 
 #: git-rebase--interactive.sh:376
 #, sh-format
 msgid "Refusing to squash a merge: $sha1"
-msgstr ""
+msgstr "\"squash\" eines Merges ($sha1) zurückgewiesen."
 
 #: git-rebase--interactive.sh:390
-#, fuzzy, sh-format
+#, sh-format
 msgid "Error redoing merge $sha1"
-msgstr "Fehler beim Erzeugen der \"Tree\"-Objekte"
+msgstr "Fehler beim Wiederholen des Merges von $sha1"
 
 #: git-rebase--interactive.sh:398
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not pick $sha1"
-msgstr "Konnte %s nicht öffnen"
+msgstr "Konnte $sha1 nicht picken"
 
 #: git-rebase--interactive.sh:407
-#, fuzzy, sh-format
+#, sh-format
 msgid "This is the commit message #${n}:"
-msgstr "Commit-Beschreibung bearbeiten"
+msgstr "Das ist Commit-Beschreibung #${n}:"
 
 #: git-rebase--interactive.sh:412
-#, fuzzy, sh-format
+#, sh-format
 msgid "The commit message #${n} will be skipped:"
-msgstr "Commit-Beschreibung bearbeiten"
+msgstr "Commit-Beschreibung #${n} wird ausgelassen:"
 
 #: git-rebase--interactive.sh:423
 #, sh-format
 msgid "This is a combination of $count commit."
 msgid_plural "This is a combination of $count commits."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Das ist eine Kombination aus $count Commit."
+msgstr[1] "Das ist eine Kombination aus $count Commits."
 
 #: git-rebase--interactive.sh:431
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot write $fixup_msg"
-msgstr "Kann nicht überschreiben"
+msgstr "Kann $fixup_msg nicht schreiben"
 
 #: git-rebase--interactive.sh:434
 msgid "This is a combination of 2 commits."
-msgstr ""
+msgstr "Das ist eine Kombination aus 2 Commits."
 
 #: git-rebase--interactive.sh:435
-#, fuzzy
 msgid "This is the 1st commit message:"
-msgstr "Commit-Beschreibung bearbeiten"
+msgstr "Das ist die erste Commit-Beschreibung:"
 
 #: git-rebase--interactive.sh:475 git-rebase--interactive.sh:518
 #: git-rebase--interactive.sh:521
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not apply $sha1... $rest"
-msgstr "Konnte %s... (%s) nicht anwenden"
+msgstr "Konnte $sha1... ($rest) nicht anwenden"
 
 #: git-rebase--interactive.sh:549
 #, sh-format
 msgid ""
 "Could not amend commit after successfully picking $sha1... $rest\n"
 "This is most likely due to an empty commit message, or the pre-commit hook\n"
 "failed. If the pre-commit hook failed, you may need to resolve the issue "
 "before\n"
 "you are able to reword the commit."
 msgstr ""
+"Konnte Commit nicht nachbessern, nachdem dieser verwendet wurde: $sha1... $rest\n"
+"Das passierte sehr wahrscheinlich wegen einer leeren Commit-Beschreibung, oder\n"
+"weil der pre-commit Hook fehlschlug. Falls der pre-commit Hook fehlschlug,\n"
+"sollten Sie das Problem beheben, bevor Sie die Commit-Beschreibung ändern können."
 
 #: git-rebase--interactive.sh:564
 #, sh-format
 msgid "Stopped at $sha1_abbrev... $rest"
-msgstr ""
+msgstr "Angehalten bei $sha1_abbrev... $rest"
 
 #: git-rebase--interactive.sh:579
 #, sh-format
 msgid "Cannot '$squash_style' without a previous commit"
-msgstr ""
+msgstr "Kann nicht '$squash_style' ohne vorherigen Commit"
 
 #: git-rebase--interactive.sh:621
 #, sh-format
 msgid "Executing: $rest"
-msgstr ""
+msgstr "Führe aus: $rest"
 
 #: git-rebase--interactive.sh:629
 #, sh-format
 msgid "Execution failed: $rest"
-msgstr ""
+msgstr "Ausführung fehlgeschlagen: $rest"
 
 #: git-rebase--interactive.sh:631
-#, fuzzy
 msgid "and made changes to the index and/or the working tree"
-msgstr "weder den Index, noch das Arbeitsverzeichnis aktualisieren"
+msgstr "Der Index und/oder das Arbeitsverzeichnis wurde geändert."
 
 #: git-rebase--interactive.sh:633
-#, fuzzy
 msgid ""
 "You can fix the problem, and then run\n"
 "\n"
 "\tgit rebase --continue"
 msgstr ""
-"  (beheben Sie die Konflikte und führen Sie dann \"git rebase --continue\" "
-"aus)"
+"Sie können das Problem beheben, und dann\n"
+"\n"
+"\tgit rebase --continue\n"
+"\n"
+"ausführen."
 
 #. TRANSLATORS: after these lines is a command to be issued by the user
 #: git-rebase--interactive.sh:646
 #, sh-format
 msgid ""
 "Execution succeeded: $rest\n"
 "but left changes to the index and/or the working tree\n"
 "Commit or stash your changes, and then run\n"
 "\n"
 "\tgit rebase --continue"
 msgstr ""
+"Ausführung erfolgreich: $rest\n"
+"Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
+"Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
+"Führen Sie dann aus:\n"
+"\n"
+"\tgit rebase --continue"
 
 #: git-rebase--interactive.sh:657
-#, fuzzy, sh-format
+#, sh-format
 msgid "Unknown command: $command $sha1 $rest"
-msgstr "Unbekannter Unterbefehl: %s"
+msgstr "Unbekannter Befehl: $command $sha1 $rest"
 
 #: git-rebase--interactive.sh:658
 msgid "Please fix this using 'git rebase --edit-todo'."
-msgstr ""
+msgstr "Bitte beheben Sie das, indem Sie 'git rebase --edit-todo' ausführen."
 
 #: git-rebase--interactive.sh:693
 #, sh-format
 msgid "Successfully rebased and updated $head_name."
-msgstr ""
+msgstr "Erfolgreich Rebase ausgeführt und $head_name aktualisiert."
 
 #: git-rebase--interactive.sh:740
 msgid "Could not skip unnecessary pick commands"
-msgstr ""
+msgstr "Fehler beim Auslassen von nicht erforderlichen \"pick\"-Befehlen."
 
 #: git-rebase--interactive.sh:898
 #, sh-format
 msgid ""
 "Warning: the SHA-1 is missing or isn't a commit in the following line:\n"
 " - $line"
 msgstr ""
+"Warnung: Der SHA-1 in der folgenden Zeile fehlt oder ist kein Commit:\n"
+" - $line"
 
 #: git-rebase--interactive.sh:931
 #, sh-format
 msgid ""
 "Warning: the command isn't recognized in the following line:\n"
 " - $line"
 msgstr ""
+"Warnung: Das Kommando in der folgenden Zeile wurde nicht erkannt:\n"
+" - $line"
 
 #: git-rebase--interactive.sh:970
-#, fuzzy
 msgid "could not detach HEAD"
-msgstr "Konnte nicht von %s anfordern"
+msgstr "Konnte HEAD nicht loslösen"
 
 #: git-rebase--interactive.sh:1008
 msgid ""
 "Warning: some commits may have been dropped accidentally.\n"
 "Dropped commits (newer to older):"
 msgstr ""
+"Warnung: Einige Commits könnten aus Versehen entfernt worden sein.\n"
+"Entfernte Commits (neu zu alt):"
 
 #: git-rebase--interactive.sh:1016
 msgid ""
 "To avoid this message, use \"drop\" to explicitly remove a commit.\n"
 "\n"
 "Use 'git config rebase.missingCommitsCheck' to change the level of "
 "warnings.\n"
 "The possible behaviours are: ignore, warn, error."
 msgstr ""
+"Um diese Meldung zu vermeiden, benutzen Sie \"drop\", um exlizit Commits zu\n"
+"entfernen.\n"
+"\n"
+"Benutzen Sie 'git config rebase.missingCommitsCheck', um die Stufe der Warnungen\n"
+"zu ändern.\n"
+"Die möglichen Verhaltensweisen sind: ignore, warn, error."
 
 #: git-rebase--interactive.sh:1027
 #, sh-format
 msgid ""
 "Unrecognized setting $check_level for option rebase.missingCommitsCheck. "
 "Ignoring."
 msgstr ""
+"Nicht erkannte Einstellung $check_level für Option rebase.missingCommitsCheck.\n"
+"Ignoriere."
 
 #: git-rebase--interactive.sh:1044
 msgid "You can fix this with 'git rebase --edit-todo'."
-msgstr ""
+msgstr "Sie können das mit 'git rebase --edit-todo' beheben."
 
 #: git-rebase--interactive.sh:1045
 msgid "Or you can abort the rebase with 'git rebase --abort'."
-msgstr ""
+msgstr "Oder Sie können den Rebase mit 'git rebase --abort' abbrechen."
 
 #: git-rebase--interactive.sh:1069
-#, fuzzy
 msgid "Could not remove CHERRY_PICK_HEAD"
-msgstr "Konnte Commit von HEAD nicht auflösen\n"
+msgstr "Konnte CHERRY_PICK_HEAD nicht löschen"
 
 #: git-rebase--interactive.sh:1074
 #, sh-format
 msgid ""
 "You have staged changes in your working tree.\n"
 "If these changes are meant to be\n"
 "squashed into the previous commit, run:\n"
 "\n"
 "  git commit --amend $gpg_sign_opt_quoted\n"
 "\n"
 "If they are meant to go into a new commit, run:\n"
 "\n"
 "  git commit $gpg_sign_opt_quoted\n"
 "\n"
 "In both case, once you're done, continue with:\n"
 "\n"
 "  git rebase --continue\n"
 msgstr ""
+"Es befinden sich zum Commit vorgemerkte Änderungen in Ihrem Arbeitsverzeichnis.\n"
+"Wenn diese Änderungen in den vorherigen Commit aufgenommen werden sollen,\n"
+"führen Sie aus:\n"
+"\n"
+"  git commit --amend $gpg_sign_opt_quoted\n"
+"\n"
+"Wenn daraus ein neuer Commit erzeugt werden soll, führen Sie aus:\n"
+"\n"
+"  git commit $gpg_sign_opt_quoted\n"
+"\n"
+"Im Anschluss führen Sie zum Fortfahren aus:\n"
+"\n"
+"  git rebase --continue\n"
 
 #: git-rebase--interactive.sh:1091
 msgid "Error trying to find the author identity to amend commit"
 msgstr ""
+"Fehler beim Versuch die Identität des Authors zum Verbessern des Commits zu\n"
+"finden"
 
 #: git-rebase--interactive.sh:1096
 msgid ""
 "You have uncommitted changes in your working tree. Please commit them\n"
 "first and then run 'git rebase --continue' again."
 msgstr ""
+"Sie haben nicht committete Änderungen in Ihrem Arbeitsverzeichnis. Bitte\n"
+"committen Sie diese zuerst und führen Sie dann 'git rebase --continue' erneut\n"
+"aus."
 
 #: git-rebase--interactive.sh:1101 git-rebase--interactive.sh:1105
-#, fuzzy
 msgid "Could not commit staged changes."
-msgstr "Konnte Commit-Beschreibung nicht lesen: %s"
+msgstr "Konnte Änderungen aus der Staging-Area nicht committen."
 
 #: git-rebase--interactive.sh:1129
 msgid ""
 "\n"
 "You are editing the todo file of an ongoing interactive rebase.\n"
 "To continue rebase after editing, run:\n"
 "    git rebase --continue\n"
 "\n"
 msgstr ""
+"\n"
+"Sie bearbeiten gerade die TODO-Datei eines laufenden interaktiven Rebase.\n"
+"Um den Rebase nach dem Editieren fortzusetzen, führen Sie aus:\n"
+"    git rebase --continue\n"
+"\n"
 
 #: git-rebase--interactive.sh:1137 git-rebase--interactive.sh:1298
-#, fuzzy
 msgid "Could not execute editor"
-msgstr "Konnte %s nicht entfernen"
+msgstr "Konnte Editor nicht ausführen."
 
 #: git-rebase--interactive.sh:1145
 msgid "You need to set your committer info first"
 msgstr "Sie müssen zuerst die Informationen zum Commit-Ersteller setzen."
 
 #: git-rebase--interactive.sh:1153
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not checkout $switch_to"
-msgstr "Konnte Verzeichnis '%s' nicht erstellen."
+msgstr "Konnte $switch_to nicht auschecken."
 
 #: git-rebase--interactive.sh:1158
 msgid "No HEAD?"
-msgstr ""
+msgstr "Kein HEAD?"
 
 #: git-rebase--interactive.sh:1159
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not create temporary $state_dir"
-msgstr "konnte temporäre Datei '%s' nicht erstellen"
+msgstr "Konnte temporäres Verzeichnis $state_dir nicht erstellen."
 
 #: git-rebase--interactive.sh:1161
-#, fuzzy
 msgid "Could not mark as interactive"
-msgstr "Konnte Bereitstellung nicht lesen"
+msgstr "Konnte nicht als interaktiven Rebase markieren."
 
 #: git-rebase--interactive.sh:1171 git-rebase--interactive.sh:1176
-#, fuzzy
 msgid "Could not init rewritten commits"
-msgstr "Konnte Eltern-Commit %s nicht parsen\n"
+msgstr "Konnte neu geschriebene Commits nicht initialisieren."
 
 #: git-rebase--interactive.sh:1276
 #, sh-format
 msgid "Rebase $shortrevisions onto $shortonto ($todocount command)"
 msgid_plural "Rebase $shortrevisions onto $shortonto ($todocount commands)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Rebase von $shortrevisions auf $shortonto ($todocount Kommando)"
+msgstr[1] "Rebase von $shortrevisions auf $shortonto ($todocount Kommandos)"
 
 #: git-rebase--interactive.sh:1281
 msgid ""
 "\n"
 "However, if you remove everything, the rebase will be aborted.\n"
 "\n"
-msgstr ""
+msgstr "\nWenn Sie jedoch alles löschen, wird der Rebase abgebrochen.\n\n"
 
 #: git-rebase--interactive.sh:1288
 msgid "Note that empty commits are commented out"
-msgstr ""
+msgstr "Leere Commits sind auskommentiert."
 
 #: git-sh-setup.sh:89 git-sh-setup.sh:94
 #, sh-format
 msgid "usage: $dashless $USAGE"
-msgstr ""
+msgstr "Verwendung: $dashless $USAGE"
 
 #: git-sh-setup.sh:190
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot chdir to $cdup, the toplevel of the working tree"
 msgstr ""
-"Relative Pfade können nur von der obersten Ebene des Arbeitsverzeichnisses "
-"benutzt werden."
+"Konnte nicht in Verzeichnis $cdup wechseln, der obersten Ebene des\n"
+"Arbeitsverzeichnisses."
 
 #: git-sh-setup.sh:199 git-sh-setup.sh:206
 #, sh-format
 msgid "fatal: $program_name cannot be used without a working tree."
-msgstr ""
+msgstr "fatal: $program_name kann ohne ein Arbeitsverzeichnis nicht verwendet werden."
 
 #: git-sh-setup.sh:220
-#, fuzzy
 msgid "Cannot rebase: You have unstaged changes."
-msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Sie haben Änderungen, die "
-"nicht zum Commit vorgemerkt sind."
+msgstr "Rebase nicht möglich: Sie haben Änderungen, die nicht zum Commit vorgemerkt sind."
 
 #: git-sh-setup.sh:223
-#, fuzzy
 msgid "Cannot rewrite branches: You have unstaged changes."
 msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Sie haben Änderungen, die "
-"nicht zum Commit vorgemerkt sind."
+"Kann Branches nicht neu schreiben: Sie haben Änderungen, die nicht zum Commit\n"
+"vorgemerkt sind."
 
 #: git-sh-setup.sh:229
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot $action: You have unstaged changes."
 msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Sie haben Änderungen, die "
-"nicht zum Commit vorgemerkt sind."
+"Kann $action nicht ausführen: Sie haben Änderungen, die nicht zum Commit\n"
+"vorgemerkt sind."
 
 #: git-sh-setup.sh:242
-#, fuzzy
 msgid "Cannot rebase: Your index contains uncommitted changes."
-msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Die Staging-Area beinhaltet "
-"nicht committete Änderungen."
+msgstr "Rebase nicht möglich: Die Staging-Area beinhaltet nicht committete Änderungen."
 
 #: git-sh-setup.sh:248
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot $action: Your index contains uncommitted changes."
 msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Die Staging-Area beinhaltet "
-"nicht committete Änderungen."
+"Kann $action nicht ausführen: Die Staging-Area beinhaltet nicht committete\n"
+"Änderungen."
 
 #: git-sh-setup.sh:372
-#, fuzzy
 msgid "You need to run this command from the toplevel of the working tree."
-msgstr ""
-"Relative Pfade können nur von der obersten Ebene des Arbeitsverzeichnisses "
-"benutzt werden."
+msgstr "Sie müssen den Befehl von der obersten Ebene des Arbeitsverzeichnisses ausführen."
 
 #: git-sh-setup.sh:377
-#, fuzzy
 msgid "Unable to determine absolute path of git directory"
-msgstr "Konnte aktuelles Arbeitsverzeichnis nicht bekommen."
+msgstr "Konnte absoluten Pfad des Git-Verzeichnisses nicht bestimmen."
 
-- 
2.10.1.484.gd4ef107


^ permalink raw reply related	[relevance 1%]

* Re: "Purposes, Concepts,Misfits, and a Redesign of Git" (a research paper)
  2016-10-05 10:14  3%     ` Jakub Narębski
@ 2016-10-05 10:42  0%       ` Duy Nguyen
  0 siblings, 0 replies; 200+ results
From: Duy Nguyen @ 2016-10-05 10:42 UTC (permalink / raw)
  To: Jakub Narębski
  Cc: Santiago Perez De Rosso, Konstantin Khomoutov, git,
	Daniel Jackson, Greg Wilson

On Wed, Oct 5, 2016 at 5:14 PM, Jakub Narębski <jnareb@gmail.com> wrote:
> [git@vger.kernel.org does not accept HTML emails]
>
> I just hope that this email don't get mangled too much...
>
> On 5 October 2016 at 04:55, Santiago Perez De Rosso
> <sperezde@csail.mit.edu> wrote:
>> On Fri, Sep 30, 2016 at 6:25 PM Jakub Narębski <jnareb@gmail.com> wrote:
>>> W dniu 30.09.2016 o 18:14, Konstantin Khomoutov pisze:
>>>
>>>> The "It Will Never Work in Theory" blog has just posted a summary of a
>>>> study which tried to identify shortcomings in the design of Git.
>>>>
>>>> In the hope it might be interesting, I post this summary here.
>>>> URL: http://neverworkintheory.org/2016/09/30/rethinking-git.html
>>>
>>> I will comment on the article itself, not just on the summary.
>>>
>>> | 2.2 Git
>>> [...]
>>> | But tracked files cannot be ignored; to ignore a tracked file
>>> | one has to mark it as “assume unchanged.” This “assume
>>> | unchanged” file will not be recognized by add; to make it
>>> | tracked again this marking has to be removed.
>>>
>>> WRONG!  Git has tracked files, untracked unignored files, and
>>> untracked ignored files (mostly considered unimportant).
>>>
>>> The "assume unchanged" bit is _performance_ optimization. It is not,
>>> and cannot be a 'ignore tracked files' bit - here lies lost work!!!
>>> You can use (imperfectly) "prefer worktree" bit hack instead.
>>>
>>> You can say, if 'ignoring change to tracked files' is motivation,
>>> or purpose, it lacks direct concept.
>>
>>
>> I don't see what's wrong with the paragraph you mention. I am aware of the
>> fact that assumed unchanged is intended to be used as a performance
>> optimization but that doesn't seem to be the way it is used in practice.
>> Users have appropriated the optimization and effectively turned into a
>> concept that serves the purpose of preventing the commit of a file. For
>> example:
>>
>> from http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html
>>
>>  So, to temporarily ignore changes in a certain file, run:
>>  git update-index --assume-unchanged <file>
>>  ...
>>
>> from http://stackoverflow.com/questions/17195861/undo-git-update-index-assume-unchanged-file
>>  The way you git ignore watching/tracking a particular dir/file.
>>  you just run this:
>>  git update-index --assume-unchanged <file>
>> ...
>>
>>
>> btw, this appropriation suggests that users want to be able to ignore
>> tracked files and they do what they can with what they are given (which
>> in this case means abusing the assumed unchanged bit).
>
> Yes, this is true that users may want to be able to ignore changes to
> tracked files (commit with dirty tree), but using `assume-unchanged` is
> wrong and dangerous solution.  Unfortunately the advice to use it is
> surprisingly pervasive.  I would thank you to not further this error.
> (Well, `skip-worktree` is newer, that's why it is lesser known, perhaps)
>
> To ignore tracked files you need to use `skip-worktree` bit.
>
> You can find the difference between `assume-unchanged` and
> `skip-worktree`, and when use which in:
> http://stackoverflow.com/questions/13630849/git-difference-between-assume-unchanged-and-skip-worktree
> http://fallengamer.livejournal.com/93321.html
> http://blog.stephan-partzsch.de/how-to-ignore-changes-in-tracked-files-with-git/
>
> The difference is that skip-worktree will not overwrite a file that is
> different from the version in the index, but assume-unchanged can.  This
> means that the latter can OVERWRITE YOUR PRECIOUS CHANGES!
>
> Some people started to recommend it
> http://stackoverflow.com/questions/32251037/ignore-changes-to-a-tracked-file
> http://www.virtuouscode.com/2011/05/20/keep-local-modifications-in-git-tracked-files/

And since skip-worktree bits may be set/cleared freely when sparse
checkout mode is on, you should never manipulate these bits directly
if you also use sparse checkout.

>>> | *Detached Head* Suppose you are working on some branch
>>> | and realize that the last few commits you did are wrong, so
>>> | you decide to go back to an old commit to start over again.
>>> | You checkout that old commit and keep working creating
>>> | commits. You might be surprised to discover that these new
>>> | commits you’ve been working on belong to no branch at all.
>>> | To avoid losing them you need to create a new branch or reset
>>> | an existing one to point to the last commit.
>>>
>>> It would be hard to be surprised unless one is in habit of
>>> disregarding multi-line warning from Git... ;-)
>>
>> True if you are an expert user, but I can assure you novices will
>> find that situation baffling, even with the multi-line warnings.

Hmm...  when you switch away from a detached HEAD, you are advised to
do "git branch <new-name> blah blah". How is it baffling? Genuine
question, maybe I have been using git for too long I just fail to see
it.

> True, the "detached HEAD" case (aka "unnamed branch") can be puzzling
> for Git users, and it has few uses (e.g. checking out the state of
> tag temporarily, to test it).
>
> I wonder if `git status` should be enhanced to tell user how to get
> out of "detached HEAD" situation -- it has lots of advices in it.

Detached HEAD is also present in interactive rebase or any command
that has --abort/--continue options. I don't think we need to tell the
user to get out of detached HEAD in that case. Just two cents if
someone is going to add this advice to git-status.
-- 
Duy

^ permalink raw reply	[relevance 0%]

* Re: "Purposes, Concepts,Misfits, and a Redesign of Git" (a research paper)
       [not found]       ` <CAKbZu+BUOAjixTmEC4octseyJbMnFuaCTtLT9hx3H10=AECeKw@mail.gmail.com>
@ 2016-10-05 10:14  3%     ` Jakub Narębski
  2016-10-05 10:42  0%       ` Duy Nguyen
  0 siblings, 1 reply; 200+ results
From: Jakub Narębski @ 2016-10-05 10:14 UTC (permalink / raw)
  To: Santiago Perez De Rosso
  Cc: Konstantin Khomoutov, git, Daniel Jackson, Greg Wilson

[git@vger.kernel.org does not accept HTML emails]

I just hope that this email don't get mangled too much...

On 5 October 2016 at 04:55, Santiago Perez De Rosso
<sperezde@csail.mit.edu> wrote:
> On Fri, Sep 30, 2016 at 6:25 PM Jakub Narębski <jnareb@gmail.com> wrote:
>> W dniu 30.09.2016 o 18:14, Konstantin Khomoutov pisze:
>>
>>> The "It Will Never Work in Theory" blog has just posted a summary of a
>>> study which tried to identify shortcomings in the design of Git.
>>>
>>> In the hope it might be interesting, I post this summary here.
>>> URL: http://neverworkintheory.org/2016/09/30/rethinking-git.html
>>
>> I will comment on the article itself, not just on the summary.
>>
>> | 2.2 Git
>> [...]
>> | But tracked files cannot be ignored; to ignore a tracked file
>> | one has to mark it as “assume unchanged.” This “assume
>> | unchanged” file will not be recognized by add; to make it
>> | tracked again this marking has to be removed.
>>
>> WRONG!  Git has tracked files, untracked unignored files, and
>> untracked ignored files (mostly considered unimportant).
>>
>> The "assume unchanged" bit is _performance_ optimization. It is not,
>> and cannot be a 'ignore tracked files' bit - here lies lost work!!!
>> You can use (imperfectly) "prefer worktree" bit hack instead.
>>
>> You can say, if 'ignoring change to tracked files' is motivation,
>> or purpose, it lacks direct concept.
>
>
> I don't see what's wrong with the paragraph you mention. I am aware of the
> fact that assumed unchanged is intended to be used as a performance
> optimization but that doesn't seem to be the way it is used in practice.
> Users have appropriated the optimization and effectively turned into a
> concept that serves the purpose of preventing the commit of a file. For
> example:
>
> from http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html
>
>  So, to temporarily ignore changes in a certain file, run:
>  git update-index --assume-unchanged <file>
>  ...
>
> from http://stackoverflow.com/questions/17195861/undo-git-update-index-assume-unchanged-file
>  The way you git ignore watching/tracking a particular dir/file.
>  you just run this:
>  git update-index --assume-unchanged <file>
> ...
>
>
> btw, this appropriation suggests that users want to be able to ignore
> tracked files and they do what they can with what they are given (which
> in this case means abusing the assumed unchanged bit).

Yes, this is true that users may want to be able to ignore changes to
tracked files (commit with dirty tree), but using `assume-unchanged` is
wrong and dangerous solution.  Unfortunately the advice to use it is
surprisingly pervasive.  I would thank you to not further this error.
(Well, `skip-worktree` is newer, that's why it is lesser known, perhaps)

To ignore tracked files you need to use `skip-worktree` bit.

You can find the difference between `assume-unchanged` and
`skip-worktree`, and when use which in:
http://stackoverflow.com/questions/13630849/git-difference-between-assume-unchanged-and-skip-worktree
http://fallengamer.livejournal.com/93321.html
http://blog.stephan-partzsch.de/how-to-ignore-changes-in-tracked-files-with-git/

The difference is that skip-worktree will not overwrite a file that is
different from the version in the index, but assume-unchanged can.  This
means that the latter can OVERWRITE YOUR PRECIOUS CHANGES!

Some people started to recommend it
http://stackoverflow.com/questions/32251037/ignore-changes-to-a-tracked-file
http://www.virtuouscode.com/2011/05/20/keep-local-modifications-in-git-tracked-files/


>> | The notion of a “remote branch” must not be confused
>> | with that of an “upstream branch.” An upstream branch is
>> | just a convenience for users: after the user assigns it to some
>> | branch, commands like pull and push default to use that
>> | branch for fetching and pushing changes if no branch is given
>> | as input.
>>
>> Actually "upstream branch" (and related "upstream repository")
>> are a concept, not only a convenience. They denote a branch
>> (usually in remote repository) which is intended to ultimately
>> include changes in given branch. Note that "upstream branch"
>> can be set separately for any given local branch.
>
>
> We never say upstream branch is not a concept. It even appears in the
> table.

Hmmm... I got onfused by words "is just a convenience", which for me
implies that it is not a concept.

>>
>>
>> One thing that can enormously help recovering from errors, and
>> is not covered in the list of concepts is REFLOG.
>
>
> Yes, the analysis is not exhaustive, there are other concepts missing
> too (e.g., "submodule")

I think reflog is something that every user should know about, and
useful for all.  Submodules and subtrees is something situational,
needed only for a subset of users.

On the other hand the concept of "submodules" is something that it is
under active development, and it is assumed to be immature.  So coming
up with a good (re)design for this feature, and/or good set of
concept, would be a very good thing.


Another thing that it is not present is the concept of "immutable
history", and how to deal with it (`git-notes`, `git-replace`), and
how it conflict with other concepts (interactive rebase and the
concept of "rewriting history").  But I agree with focusing on most
commonly known, used and encountered concepts and misfits.

>> [...]
>> | 3. Operational Misfits
>> [...]
>> | *Saving Changes* Suppose you are in the middle of a long
>> | task and want to save your changes, so that they can be later
>> | retrieved in case of failure. How would you do that?
>>
>> You would use `git stash` or `git stash --include-untracked`!
>> In more complicated situations (during long-running operation
>> like resolving merge conflicts, interactive rebase, or finding
>> bugs with bisect) with modern Git you can create a new separate
>> working area with `git worktree`.
>
> A general comment regarding misfits: misfits correspond to scenarios
> in which Git behaves in a way that is unpredictable or inconvenient.
> It doesn't mean that a task has to be impossible to do in order for
> something to be a misfit.

If there were one-command solution, and the problem was that users
don't know about it, I would say that it is not a misfit.  But,
admittedly, it is not the case here...

>> | *Detached Head* Suppose you are working on some branch
>> | and realize that the last few commits you did are wrong, so
>> | you decide to go back to an old commit to start over again.
>> | You checkout that old commit and keep working creating
>> | commits. You might be surprised to discover that these new
>> | commits you’ve been working on belong to no branch at all.
>> | To avoid losing them you need to create a new branch or reset
>> | an existing one to point to the last commit.
>>
>> It would be hard to be surprised unless one is in habit of
>> disregarding multi-line warning from Git... ;-)
>
> True if you are an expert user, but I can assure you novices will
> find that situation baffling, even with the multi-line warnings.

True, the "detached HEAD" case (aka "unnamed branch") can be puzzling
for Git users, and it has few uses (e.g. checking out the state of
tag temporarily, to test it).

I wonder if `git status` should be enhanced to tell user how to get
out of "detached HEAD" situation -- it has lots of advices in it.

>> [...]
>> | The problem
>> | is the lack of connection between this purpose and the highlevel
>> | purposes for version control, which suggests that the
>> | introduction of stashing might be to patch flaws in the design
>> | of Git and not to satisfy a requirement of version control.
>>
>> Or the problem might be that you are missing some (maybe minor)
>> requirement of version control system. Just saying...
>
> What would that purpose be? and why would you say that's a
> high-level purpose for version control and not one that's
> git-specific?

The stash (or rather its equivalent) is not something Git specific.
It is present also in other version control systems, among others:

* Mercurial: as 'shelve' extension (in core since 1.8)
* Bazaar: as 'bzr shelve' command
* Fossil: as 'fossil stash' command (with subcommands)
* Subversion: Shelve planned for 1.10 (2017?)

I would say that 'stash' could be considered about isolating work on
different features, different sub-branch sized parallel work.

But it might be that stash doesn't have connection with highlevel
purposes for version control, and that it is purely convenience
feature.  Just playing the role of Advocatus Diaboli (important in
scientific works, isn' it?)...

>> [...]
>> | 7. Gitless
>> |
>> | 7.1 Overview
>> |
>> | Gitless has no staging area, and the only file classifications
>> | are “tracked,” “untracked,” “ignored,” and “in conflict.”
>>
>> Without staging area, I wonder how you would be able to handle
>> well different types of integration conflicts, which are not
>> limited to CONFLICT(content).
>>
>> You also loose the ability to select subset of *changes* to
>> be committed, not only files.  This is often very useful, see
>> http://tomayko.com/writings/the-thing-about-git
>> http://2ndscale.com/rtomayko/2008/the-thing-about-git
>
> This is described later:

Right, my mistake, I have missed this.  I should have read article in
full, then respond, rather than reply as I go...

> Common use cases for the staging area in Git are to select files to commit,
> split up a large change into multiple commits, and review the changes
> selected to be committed. We address the first by providing a more flexible
> commit command that lets the user easily customize the set of files to
> commit (with only, include and exclude flags). For the second use case we
> have a partial flag in commit that allows the user to interactively select
> segments of files to commit (like Git’s commit --patch). Finally, our diff
> command accepts the same only, include and exclude flags to customize the
> set of files to be diffed. There could be other use cases for the staging
> area that Gitless doesn’t handle well but we expect these to be fairly
> infrequent.

I wrote later that Git offers more flexibility with respect of
interactive edition of the staging area (additive, substractive, from
HEAD, from arbitrary commit) and checking the prepared state (add <->
diff <-> stash --keep-index + test + unstash)... but I think this is a
matter of implementing interface for those fetures to 'partial'
commit.  It might be less flexible, and less powerfull, but it would
be there.

> Note that Gitless is built on top of Git so we do have a staging area, the
> difference is that unlike Git, in Gitless the index is hidden from the user.

All right.

I have just an idea of using the index (or rather its extensions) to
implement sub-commit history (forgotten after committing), as a way to
resolve misfit about "commit" concept and (P1) vs (P2) purposes...

>> [...]
>> |  Also, there
>> | is no possible way of getting in a “detached head” state; at
>> | any time, the user is always working on some branch (the
>> | “current” branch). Head is a per-branch reference to the last
>> | commit of the branch.
>>
>> How do you solve the problem of checking out the state of
>> the tag, that is the state of repository at given revision?
>
> You can't checkout a tag, you would have to create a new branch with
> its head equal to the tag, and switch to that branch.

For the purpose of testing a state at a tag (for example as a
prerequisite to bisection), it fills like unnecessarily complicated
solution, a new misfit.  But I guess that you consider "detached HEAD"
misfit to be more important to get rid of.

>> Also during some long lived multi-step operations, like bisect
>> or interactive rebase, you are not really on any branch,
>
> In Gitless we don't have bisect but for rebase (fuse in Gitless) we
> record the current branch.

No bisect?  This is very useful feature.  Though it might be done
without detached HEAD, but with specialized pseudo-branch 'bisect' (as
it was done in earlier versions of Git, or maybe even now).

Anyway, for [interactive] rebase / transplant / graft / fuse you need
to be able to abort an operation and return to the state before
staring rebase.  Though you can or do solve this by remembering
the starting position.

>> | 7.2.1 Discussion
>> [...]
>> | There could be other use cases for the
>> | staging area that Gitless doesn’t handle well but we expect
>> | these to be fairly infrequent.
>>
>> Like handling merge conflict...??? Infrequent doesn't mean
>> unimportant.
>
> I regard handling merge conflicts as very important. Why do you need
> an explicit staging area for this? Note that Gitless has a staging
> area, it's just hidden from the user. The `gl diff` or `gl status`
> command should be able to show the same conflict information.

Well, the staging area was created (also?) to handle merges.  Though
perhaps it doesn't need to be explicit to be useful...

Best regards,
-- 
Jakub Narębski

^ permalink raw reply	[relevance 3%]

* [PATCH] l10n: de.po: translate 260 new messages
@ 2016-10-02 16:59  1% Ralf Thielow
  2016-10-07 16:45  1% ` [PATCH v2] " Ralf Thielow
  0 siblings, 1 reply; 200+ results
From: Ralf Thielow @ 2016-10-02 16:59 UTC (permalink / raw)
  To: git
  Cc: tr, jk, stimming, phillip.szelat, matthias.ruester,
	magnus.goerlitz, Ralf Thielow

Translate 260 new message came from git.pot updates in 9fa976f (l10n:
git.pot: v2.10.0 round 1 (248 new, 56 removed)) and 5bd166d (l10n:
git.pot: v2.10.0 round 2 (12 new, 44 removed)).

Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
---
 po/de.po | 783 ++++++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 421 insertions(+), 362 deletions(-)

diff --git a/po/de.po b/po/de.po
index e1865c6..4415c0d 100644
--- a/po/de.po
+++ b/po/de.po
@@ -14,72 +14,60 @@ msgstr ""
 "Language: de\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n!=1);\n"
 
 #: advice.c:55
 #, c-format
 msgid "hint: %.*s\n"
 msgstr "Hinweis: %.*s\n"
 
 #: advice.c:83
-#, fuzzy
 msgid "Cherry-picking is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Cherry-Picken ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:85
-#, fuzzy
 msgid "Committing is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Committen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:87
-#, fuzzy
 msgid "Merging is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Mergen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:89
-#, fuzzy
 msgid "Pulling is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Pullen ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:91
-#, fuzzy
 msgid "Reverting is not possible because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "Reverten ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:93
-#, fuzzy, c-format
+#, c-format
 msgid "It is not possible to %s because you have unmerged files."
-msgstr ""
-"\"pull\" ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
+msgstr "%s ist nicht möglich, weil Sie nicht zusammengeführte Dateien haben."
 
 #: advice.c:101
 msgid ""
 "Fix them up in the work tree, and then use 'git add/rm <file>'\n"
 "as appropriate to mark resolution and make a commit."
 msgstr ""
 "Korrigieren Sie dies im Arbeitsverzeichnis, und benutzen Sie\n"
 "dann 'git add/rm <Datei>', um die Auflösung entsprechend zu markieren\n"
 "und zu committen."
 
 #: advice.c:109
-#, fuzzy
 msgid "Exiting because of an unresolved conflict."
-msgstr "Beende wegen nicht abgeschlossenem Merge."
+msgstr "Beende wegen unaufgelöstem Konflikt."
 
 #: advice.c:114 builtin/merge.c:1181
 msgid "You have not concluded your merge (MERGE_HEAD exists)."
 msgstr "Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert)."
 
 #: advice.c:116
 msgid "Please, commit your changes before merging."
 msgstr "Bitte committen Sie Ihre Änderungen, bevor Sie mergen."
 
 #: advice.c:117
 msgid "Exiting because of unfinished merge."
 msgstr "Beende wegen nicht abgeschlossenem Merge."
@@ -90,24 +78,38 @@ msgid ""
 "Note: checking out '%s'.\n"
 "\n"
 "You are in 'detached HEAD' state. You can look around, make experimental\n"
 "changes and commit them, and you can discard any commits you make in this\n"
 "state without impacting any branches by performing another checkout.\n"
 "\n"
 "If you want to create a new branch to retain commits you create, you may\n"
 "do so (now or later) by using -b with the checkout command again. Example:\n"
 "\n"
 "  git checkout -b <new-branch-name>\n"
 "\n"
 msgstr ""
+"Hinweis: Checke '%s' aus.\n"
+"\n"
+"Sie befinden sich im Zustand eines 'lösgelösten HEAD'. Sie können sich\n"
+"umschauen, experimentelle Änderungen vornehmen und diese committen, und\n"
+"Sie können alle möglichen Commits, die Sie in diesem Zustand machen,\n"
+"ohne Auswirkungen auf irgendeinen Branch verwerfen, indem Sie einen\n"
+"weiteren Checkout durchführen.\n"
+"\n"
+"Wenn Sie einen neuen Branch erstellen möchten, um Ihre erstellten Commits\n"
+"zu behalten, können Sie das (jetzt oder später) durch einen weiteren Checkout\n"
+"mit der Option -b tun. Beispiel:\n"
+"\n"
+"  git checkout -b <neuer-Branchname>\n"
+"\n"
 
 #: archive.c:12
 msgid "git archive [<options>] <tree-ish> [<path>...]"
 msgstr "git archive [<Optionen>] <Commit-Referenz> [<Pfad>...]"
 
 #: archive.c:13
 msgid "git archive --list"
 msgstr "git archive --list"
 
 #: archive.c:14
 msgid ""
 "git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"
@@ -185,165 +187,176 @@ msgstr "Repository"
 msgid "retrieve the archive from remote repository <repo>"
 msgstr "Archiv vom Remote-Repository <Repository> abrufen"
 
 #: archive.c:453 builtin/archive.c:92 builtin/notes.c:483
 msgid "command"
 msgstr "Programm"
 
 #: archive.c:454 builtin/archive.c:93
 msgid "path to the remote git-upload-archive command"
 msgstr "Pfad zum externen \"git-upload-archive\"-Programm"
 
 #: archive.c:461
-#, fuzzy
 msgid "Unexpected option --remote"
-msgstr "unerwarteter Modus $mod_dst"
+msgstr "Unerwartete Option --remote"
 
 #: archive.c:463
-#, fuzzy
 msgid "Option --exec can only be used together with --remote"
-msgstr ""
-"Die Option --ignore-missing kann nur zusammen mit --dry-run verwendet werden."
+msgstr "Die Option --exec kann nur zusammen mit --remote verwendet werden."
 
 #: archive.c:465
 msgid "Unexpected option --output"
-msgstr ""
+msgstr "Unerwartete Option --output"
 
 #: archive.c:487
-#, fuzzy, c-format
+#, c-format
 msgid "Unknown archive format '%s'"
-msgstr "Unbekanntes %.*s Format %s"
+msgstr "Unbekanntes Archivformat '%s'"
 
 #: archive.c:494
-#, fuzzy, c-format
+#, c-format
 msgid "Argument not supported for format '%s': -%d"
-msgstr "Kann \"reflog\" für '%s' nicht durchführen: %s\n"
+msgstr "Argument für Format '%s' nicht unterstützt: -%d"
 
 #: attr.c:263
 msgid ""
 "Negative patterns are ignored in git attributes\n"
 "Use '\\!' for literal leading exclamation."
 msgstr ""
 "Verneinende Muster werden in Git-Attributen ignoriert.\n"
 "Benutzen Sie '\\!' für führende Ausrufezeichen."
 
 #: bisect.c:441
-#, fuzzy, c-format
+#, c-format
 msgid "Could not open file '%s'"
-msgstr "Konnte '%s' nicht öffnen"
+msgstr "Konnte Datei '%s' nicht öffnen"
 
 #: bisect.c:446
-#, fuzzy, c-format
+#, c-format
 msgid "Badly quoted content in file '%s': %s"
-msgstr "Notizinhalte in einer Datei"
+msgstr "Ungültiger Inhalt bzgl. Anführungsstriche in Datei '%s': %s"
 
 #: bisect.c:655
-#, fuzzy, c-format
+#, c-format
 msgid "We cannot bisect more!\n"
-msgstr "keine binäre Suche im Gange"
+msgstr "Keine binäre Suche mehr möglich!\n"
 
 #: bisect.c:708
-#, fuzzy, c-format
+#, c-format
 msgid "Not a valid commit name %s"
-msgstr "%s ist kein gültiger Objekt-Name"
+msgstr "%s ist kein gültiger Commit-Name"
 
 #: bisect.c:732
 #, c-format
 msgid ""
 "The merge base %s is bad.\n"
 "This means the bug has been fixed between %s and [%s].\n"
 msgstr ""
+"Die Merge-Basis %s ist fehlerhaft.\n"
+"Das bedeutet, der Fehler wurde zwischen %s und [%s] behoben.\n"
 
 #: bisect.c:737
 #, c-format
 msgid ""
 "The merge base %s is new.\n"
 "The property has changed between %s and [%s].\n"
 msgstr ""
+"Die Merge-Basis %s ist neu.\n"
+"Das bedeutet, die Eigenschaft hat sich zwischen %s und [%s] geändert.\n"
 
 #: bisect.c:742
 #, c-format
 msgid ""
 "The merge base %s is %s.\n"
 "This means the first '%s' commit is between %s and [%s].\n"
 msgstr ""
+"Die Merge-Basis %s ist %s.\n"
+"Das bedeutet, der erste '%s' Commit befindet sich zwischen %s und [%s]\n"
 
 #: bisect.c:750
 #, c-format
 msgid ""
 "Some %s revs are not ancestor of the %s rev.\n"
 "git bisect cannot work properly in this case.\n"
 "Maybe you mistook %s and %s revs?\n"
 msgstr ""
+"Manche %s Commits sind keine Vorgänger des %s Commits.\n"
+"git bisect kann in diesem Fall nicht richtig arbeiten.\n"
+"Vielleicht verwechselten Sie %s und %s Commits?\n"
 
 #: bisect.c:763
 #, c-format
 msgid ""
 "the merge base between %s and [%s] must be skipped.\n"
 "So we cannot be sure the first %s commit is between %s and %s.\n"
 "We continue anyway."
 msgstr ""
+"Die Merge-Basis zwischen %s und [%s] muss ausgelassen werden.\n"
+"Es kann daher nicht sichergestellt werden, dass sich der\n"
+"erste %s Commit zwischen %s und %s befindet.\n"
+"Es wird dennoch fortgesetzt."
 
 #: bisect.c:798
 #, c-format
 msgid "Bisecting: a merge base must be tested\n"
-msgstr ""
+msgstr "binäre Suche: eine Merge-Basis muss geprüft werden\n"
 
 #: bisect.c:849
-#, fuzzy, c-format
+#, c-format
 msgid "a %s revision is needed"
-msgstr "%.*s ist zum Commit vorgemerkt"
+msgstr "ein %s Commit wird benötigt"
 
 #: bisect.c:866 builtin/notes.c:174 builtin/tag.c:248
 #, c-format
 msgid "could not create file '%s'"
 msgstr "konnte Datei '%s' nicht erstellen"
 
 #: bisect.c:917
-#, fuzzy, c-format
+#, c-format
 msgid "could not read file '%s'"
-msgstr "Konnte Log-Datei '%s' nicht lesen"
+msgstr "Konnte Datei '%s' nicht lesen"
 
 #: bisect.c:947
-#, fuzzy
 msgid "reading bisect refs failed"
-msgstr "Hinzufügen von Dateien fehlgeschlagen"
+msgstr "Lesen von Referenzen für binäre Suche fehlgeschlagen"
 
 #: bisect.c:967
-#, fuzzy, c-format
+#, c-format
 msgid "%s was both %s and %s\n"
-msgstr "%s folgt sowohl %s als auch %s"
+msgstr "%s war %s als auch %s\n"
 
 #: bisect.c:975
 #, c-format
 msgid ""
 "No testable commit found.\n"
 "Maybe you started with bad path parameters?\n"
 msgstr ""
+"Kein testbarer Commit gefunden.\n"
+"Vielleicht starteten Sie mit falschen Pfad-Parametern?\n"
 
 #: bisect.c:994
 #, c-format
 msgid "(roughly %d step)"
 msgid_plural "(roughly %d steps)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "(ungefähr %d Schritt)"
+msgstr[1] "(ungefähr %d Schritte)"
 
 #. TRANSLATORS: the last %s will be replaced with
 #. "(roughly %d steps)" translation
 #: bisect.c:998
 #, c-format
 msgid "Bisecting: %d revision left to test after this %s\n"
 msgid_plural "Bisecting: %d revisions left to test after this %s\n"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "binäre Suche: danach noch %d Commit zum Testen übrig %s\n"
+msgstr[1] "binäre Suche: danach noch %d Commits zum Testen übrig %s\n"
 
 #: branch.c:53
 #, c-format
 msgid ""
 "\n"
 "After fixing the error cause you may try to fix up\n"
 "the remote tracking information by invoking\n"
 "\"git branch --set-upstream-to=%s%s%s\"."
 msgstr ""
 "\n"
 "Nachdem Sie die Fehlerursache behoben haben, können Sie\n"
 "die Tracking-Informationen mit\n"
@@ -571,120 +584,117 @@ msgid "could not parse %s"
 msgstr "konnte %s nicht parsen"
 
 #: commit.c:42
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s ist kein Commit!"
 
 #: compat/obstack.c:406 compat/obstack.c:408
 msgid "memory exhausted"
 msgstr "Speicher verbraucht"
 
 #: config.c:516
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in blob %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Blob %s"
 
 #: config.c:520
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in file %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Datei %s"
 
 #: config.c:524
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in standard input"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Standard-Eingabe"
 
 #: config.c:528
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in submodule-blob %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Submodul-Blob %s"
 
 #: config.c:532
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in command line %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in Kommandozeile %s"
 
 #: config.c:536
-#, fuzzy, c-format
+#, c-format
 msgid "bad config line %d in %s"
-msgstr "Zeile %d in Konfiguration %s %s ist ungültig."
+msgstr "Ungültige Konfigurationszeile %d in %s"
 
 #: config.c:655
-#, fuzzy
 msgid "out of range"
-msgstr "Kein Commit-Bereich."
+msgstr "Außerhalb des Bereichs"
 
 #: config.c:655
-#, fuzzy
 msgid "invalid unit"
-msgstr "Ungültiger Objekt-Typ %s"
+msgstr "Ungültige Einheit"
 
 #: config.c:661
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s': %s"
 msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s': %s"
 
 #: config.c:666
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in blob %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Blob %s: %s"
 
 #: config.c:669
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in file %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Datei %s: %s"
 
 #: config.c:672
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in standard input: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Standard-Eingabe: %s"
 
 #: config.c:675
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in submodule-blob %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Submodul-Blob %s: %s"
 
 #: config.c:678
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in command line %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in Befehlszeile %s: %s"
 
 #: config.c:681
-#, fuzzy, c-format
+#, c-format
 msgid "bad numeric config value '%s' for '%s' in %s: %s"
-msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s %s: %s"
+msgstr "Ungültiger numerischer Wert '%s' für Konfiguration '%s' in %s: %s"
 
 #: config.c:768
 #, c-format
 msgid "failed to expand user dir in: '%s'"
 msgstr "Fehler beim Erweitern des Nutzerverzeichnisses in: '%s'"
 
 #: config.c:849 config.c:860
 #, c-format
 msgid "bad zlib compression level %d"
 msgstr "ungültiger zlib Komprimierungsgrad %d"
 
 #: config.c:978
 #, c-format
 msgid "invalid mode for object creation: %s"
 msgstr "Ungültiger Modus für Objekterstellung: %s"
 
 #: config.c:1312
 msgid "unable to parse command-line config"
 msgstr ""
 "Konnte die über die Befehlszeile angegebene Konfiguration nicht parsen."
 
 #: config.c:1362
-#, fuzzy
 msgid "unknown error occurred while reading the configuration files"
 msgstr ""
 "Es trat ein unbekannter Fehler beim Lesen der Konfigurationsdateien auf."
 
 #: config.c:1716
 #, c-format
 msgid "unable to parse '%s' from command-line config"
 msgstr ""
 "Konnte Wert '%s' aus der über die Befehlszeile angegebenen Konfiguration\n"
 "nicht parsen."
 
 #: config.c:1718
@@ -854,27 +864,26 @@ msgstr "Fehler beim Sammeln von Namen und Informationen zum Kernel"
 
 #: dir.c:1942
 msgid "Untracked cache is disabled on this system or location."
 msgstr ""
 "Cache für unversionierte Dateien ist auf diesem System oder\n"
 "für dieses Verzeichnis deaktiviert."
 
 #: gpg-interface.c:178
 msgid "gpg failed to sign the data"
 msgstr "gpg beim Signieren der Daten fehlgeschlagen"
 
 #: gpg-interface.c:208
-#, fuzzy
 msgid "could not create temporary file"
-msgstr "konnte temporäre Datei '%s' nicht erstellen"
+msgstr "konnte temporäre Datei nicht erstellen"
 
 #: gpg-interface.c:210
 #, c-format
 msgid "failed writing detached signature to '%s'"
 msgstr "Fehler beim Schreiben der losgelösten Signatur nach '%s'"
 
 #: grep.c:1792
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "'%s': konnte %s nicht lesen"
 
 #: grep.c:1809 builtin/clone.c:382 builtin/diff.c:84 builtin/rm.c:155
@@ -1019,32 +1028,32 @@ msgstr "verweigere, da unversionierte Dateien in '%s' verloren gehen würden"
 
 #: merge-recursive.c:796
 #, c-format
 msgid "cannot read object %s '%s'"
 msgstr "kann Objekt %s '%s' nicht lesen"
 
 #: merge-recursive.c:798
 #, c-format
 msgid "blob expected for %s '%s'"
 msgstr "Blob erwartet für %s '%s'"
 
 #: merge-recursive.c:822
-#, fuzzy, c-format
+#, c-format
 msgid "failed to open '%s': %s"
-msgstr "Fehler beim Öffnen von '%s'"
+msgstr "Fehler beim Öffnen von '%s': %s"
 
 #: merge-recursive.c:833
-#, fuzzy, c-format
+#, c-format
 msgid "failed to symlink '%s': %s"
-msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'"
+msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s': %s"
 
 #: merge-recursive.c:838
 #, c-format
 msgid "do not know what to do with %06o %s '%s'"
 msgstr "weiß nicht was mit %06o %s '%s' zu machen ist"
 
 #: merge-recursive.c:978
 msgid "Failed to execute internal merge"
 msgstr "Fehler bei Ausführung des internen Merges"
 
 #: merge-recursive.c:982
 #, c-format
@@ -1697,28 +1706,26 @@ msgstr ""
 msgid ""
 "not sending a push certificate since the receiving end does not support --"
 "signed push"
 msgstr ""
 "kein Versand des \"push\"-Zertifikates, da die Gegenseite keinen signierten\n"
 "Versand (\"--signed push\") unterstützt"
 
 #: send-pack.c:425
 msgid "the receiving end does not support --atomic push"
 msgstr "die Gegenseite unterstützt keinen atomaren Versand (\"--atomic push\")"
 
 #: send-pack.c:430
-#, fuzzy
 msgid "the receiving end does not support push options"
-msgstr ""
-"die Gegenseite unterstützt keinen signierten Versand (\"--signed push\")"
+msgstr "die Gegenseite unterstützt keine Push-Optionen"
 
 #: sequencer.c:174
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
 "nach Auflösung der Konflikte, markieren Sie die korrigierten Pfade\n"
 "mit 'git add <Pfade>' oder 'git rm <Pfade>'"
 
 #: sequencer.c:177
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
@@ -1745,27 +1752,27 @@ msgstr ""
 "Ihre lokalen Änderungen würden durch den Cherry-Pick überschrieben werden."
 
 #: sequencer.c:210
 msgid "Your local changes would be overwritten by revert."
 msgstr "Ihre lokalen Änderungen würden durch den Revert überschrieben werden."
 
 #: sequencer.c:213
 msgid "Commit your changes or stash them to proceed."
 msgstr ""
 "Committen Sie Ihre Änderungen oder benutzen Sie \"stash\", um fortzufahren."
 
 #: sequencer.c:228
-#, fuzzy, c-format
+#, c-format
 msgid "%s: fast-forward"
-msgstr "Vorspulen erlauben"
+msgstr "%s: Vorspulen"
 
 #. TRANSLATORS: %s will be "revert" or "cherry-pick"
 #: sequencer.c:303
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: Konnte neue Index-Datei nicht schreiben"
 
 #: sequencer.c:321
 msgid "Could not resolve HEAD commit\n"
 msgstr "Konnte Commit von HEAD nicht auflösen\n"
 
 #: sequencer.c:341
@@ -1829,44 +1836,38 @@ msgstr "leere Menge von Commits übergeben"
 
 #: sequencer.c:641
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: Fehler beim Lesen des Index"
 
 #: sequencer.c:645
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: Fehler beim Aktualisieren des Index"
 
 #: sequencer.c:705
-#, fuzzy
 msgid "Cannot revert during another revert."
-msgstr "Kann Zustand des Arbeitsverzeichnisses nicht aufzeichnen"
+msgstr "Kann Revert nicht während eines anderen Reverts ausführen."
 
 #: sequencer.c:706
-#, fuzzy
 msgid "Cannot revert during a cherry-pick."
-msgstr ""
-"Kann keinen Teil-Commit durchführen, während \"cherry-pick\" im Gange ist."
+msgstr "Kann Revert nicht während eines Cherry-Picks ausführen."
 
 #: sequencer.c:709
-#, fuzzy
 msgid "Cannot cherry-pick during a revert."
-msgstr "kein \"cherry-pick\" oder \"revert\" im Gang"
+msgstr "Kann Cherry-Pick nicht während eines Reverts ausführen."
 
 #: sequencer.c:710
-#, fuzzy
 msgid "Cannot cherry-pick during another cherry-pick."
-msgstr ""
-"Kann keinen Teil-Commit durchführen, während \"cherry-pick\" im Gange ist."
+msgstr "Kann Cherry-Pick nicht während eines anderen Cherry-Picks ausführen."
 
 #: sequencer.c:732
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Konnte Zeile %d nicht parsen."
 
 #: sequencer.c:737
 msgid "No commits parsed."
 msgstr "Keine Commits geparst."
 
 #: sequencer.c:749
 #, c-format
@@ -1958,87 +1959,100 @@ msgid "%s: bad revision"
 msgstr "%s: ungültiger Commit"
 
 #: sequencer.c:1102
 msgid "Can't revert as initial commit"
 msgstr "Kann nicht als allerersten Commit einen Revert ausführen."
 
 #: setup.c:160
 #, c-format
 msgid ""
 "%s: no such path in the working tree.\n"
 "Use 'git <command> -- <path>...' to specify paths that do not exist locally."
 msgstr ""
+"%s: kein solcher Pfad im Arbeitsverzeichnis.\n"
+"Benutzen Sie 'git <Befehl> -- <Pfad>...' zur Angabe von Pfaden, die lokal\n"
+"nicht existieren."
 
 #: setup.c:173
 #, c-format
 msgid ""
 "ambiguous argument '%s': unknown revision or path not in the working tree.\n"
 "Use '--' to separate paths from revisions, like this:\n"
 "'git <command> [<revision>...] -- [<file>...]'"
 msgstr ""
+"mehrdeutiges Argument '%s': unbekannter Commit oder Pfad existiert nicht\n"
+"im Arbeitsverzeichnis\n"
+"Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:\n"
+"'git <Befehl> [<Commit>...] -- [<Datei>...]'"
 
 #: setup.c:223
 #, c-format
 msgid ""
 "ambiguous argument '%s': both revision and filename\n"
 "Use '--' to separate paths from revisions, like this:\n"
 "'git <command> [<revision>...] -- [<file>...]'"
 msgstr ""
+"mehrdeutiges Argument '%s': sowohl Commit als auch Dateiname\n"
+"Benutzen Sie '--', um Pfade und Commits zu trennen, ähnlich wie:\n"
+"'git <Befehl> [<Commit>...] -- [<Datei>...]'"
 
 #: setup.c:248 builtin/apply.c:3362 builtin/apply.c:3373 builtin/apply.c:3419
 #, c-format
 msgid "failed to read %s"
 msgstr "Fehler beim Lesen von %s"
 
 #: setup.c:468
 #, c-format
 msgid "Expected git repo version <= %d, found %d"
 msgstr "Erwartete Git-Repository-Version <= %d, %d gefunden"
 
 #: setup.c:476
 msgid "unknown repository extensions found:"
 msgstr "Unbekannte Repository-Erweiterungen gefunden:"
 
 #: setup.c:762
 #, c-format
 msgid "Not a git repository (or any of the parent directories): %s"
-msgstr ""
+msgstr "Kein Git-Repository (oder irgendein Elternverzeichnis): %s"
 
 #: setup.c:764 setup.c:915 builtin/index-pack.c:1641
 msgid "Cannot come back to cwd"
 msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln"
 
 #: setup.c:845
-#, fuzzy
 msgid "Unable to read current working directory"
-msgstr "Konnte aktuelles Arbeitsverzeichnis nicht bekommen."
+msgstr "Konnte aktuelles Arbeitsverzeichnis nicht lesen."
 
 #: setup.c:920
 #, c-format
 msgid ""
 "Not a git repository (or any parent up to mount point %s)\n"
 "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."
 msgstr ""
+"Kein Git-Repository (oder irgendein Elternverzeichnis bis zum Einhängepunkt %s)\n"
+"Stoppe bei Dateisystemgrenze (GIT_DISCOVERY_ACROSS_FILESYSTEM nicht gesetzt)."
 
 #: setup.c:927
-#, fuzzy, c-format
+#, c-format
 msgid "Cannot change to '%s/..'"
-msgstr "kann nicht in Verzeichnis %s wechseln"
+msgstr "Kann nicht in Verzeichnis '%s/..' wechseln"
 
 #: setup.c:989
 #, c-format
 msgid ""
 "Problem with core.sharedRepository filemode value (0%.3o).\n"
 "The owner of files must always have read and write permissions."
 msgstr ""
+"Problem mit Wert für Dateimodus (0%.3o) von core.sharedRepository.\n"
+"Der Besitzer der Dateien muss immer Lese- und Schreibberechtigung haben."
 
 #: sha1_file.c:1046
 msgid "offset before end of packfile (broken .idx?)"
 msgstr "Offset vor Ende der Packdatei (fehlerhafte Indexdatei?)"
 
 #: sha1_file.c:2434
 #, c-format
 msgid "offset before start of pack index for %s (corrupt index?)"
 msgstr "Offset vor Beginn des Pack-Index für %s (beschädigter Index?)"
 
 #: sha1_file.c:2438
 #, c-format
@@ -2150,109 +2164,121 @@ msgid "file %s is not writable by user"
 msgstr "Datei %s ist vom Benutzer nicht beschreibbar."
 
 #: trailer.c:873
 msgid "could not open temporary file"
 msgstr "konnte temporäre Datei '%s' nicht öffnen"
 
 #: trailer.c:912
 #, c-format
 msgid "could not rename temporary file to %s"
 msgstr "konnte temporäre Datei nicht zu %s umbenennen"
 
 #: transport.c:62
-#, fuzzy, c-format
+#, c-format
 msgid "Would set upstream of '%s' to '%s' of '%s'\n"
-msgstr "Konnte Sektion '%s' in Konfiguration nicht nach '%s' umbenennen"
+msgstr "Würde Upstream-Branch von '%s' zu '%s' von '%s' setzen\n"
 
 #: transport.c:151
-#, fuzzy, c-format
+#, c-format
 msgid "transport: invalid depth option '%s'"
-msgstr "Ungültige Option für --decorate: %s"
+msgstr "transport: ungültige --depth Option '%s'"
 
 #: transport.c:771
 #, c-format
 msgid ""
 "The following submodule paths contain changes that can\n"
 "not be found on any remote:\n"
 msgstr ""
+"Die folgenden Submodul-Pfade enthalten Änderungen, die in keinem\n"
+"Remote-Repository gefunden wurden:\n"
 
 #: transport.c:775
 #, c-format
 msgid ""
 "\n"
 "Please try\n"
 "\n"
 "\tgit push --recurse-submodules=on-demand\n"
 "\n"
 "or cd to the path and use\n"
 "\n"
 "\tgit push\n"
 "\n"
 "to push them to a remote.\n"
 "\n"
 msgstr ""
+"\n"
+"Bitte versuchen Sie\n"
+"\n"
+"\tgit push --recurse-submodules=on-demand\n"
+"\n"
+"oder wechseln Sie in das Verzeichnis und benutzen Sie\n"
+"\n"
+"\tgit push\n"
+"\n"
+"zum Versenden zu einem Remote-Repository.\n"
+"\n"
 
 #: transport.c:783
-#, fuzzy
 msgid "Aborting."
-msgstr "Abbruch\n"
+msgstr "Abbruch."
 
 #: transport-helper.c:1041
 #, c-format
 msgid "Could not read ref %s"
 msgstr "Konnte Referenz %s nicht lesen."
 
 #: unpack-trees.c:64
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
 "%%sPlease commit your changes or stash them before you switch branches."
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden beim Auschecken\n"
 "überschrieben werden:\n"
-"%%sBitte committen oder stashen Sie Ihre Änderungen, bevor Sie Branches "
+"%%sBitte committen oder stashen Sie Ihre Änderungen, bevor Sie Branches\n"
 "wechseln."
 
 #: unpack-trees.c:66
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by checkout:\n"
 "%%s"
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden beim Auschecken\n"
 "überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:69
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
 "%%sPlease commit your changes or stash them before you merge."
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
 "überschrieben werden:\n"
 "%%sBitte committen oder stashen Sie Ihre Änderungen, bevor sie mergen."
 
 #: unpack-trees.c:71
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by merge:\n"
 "%%s"
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
 "überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:74
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
 "%%sPlease commit your changes or stash them before you %s."
 msgstr ""
 "Ihre lokalen Änderungen in den folgenden Dateien würden durch %s\n"
 "überschrieben werden:\n"
 "%%sBitte committen oder stashen Sie Ihre Änderungen, bevor Sie %s ausführen."
 
 #: unpack-trees.c:76
 #, c-format
 msgid ""
 "Your local changes to the following files would be overwritten by %s:\n"
@@ -2263,143 +2289,136 @@ msgstr ""
 
 #: unpack-trees.c:81
 #, c-format
 msgid ""
 "Updating the following directories would lose untracked files in it:\n"
 "%s"
 msgstr ""
 "Durch die Aktualisierung der folgenden Verzeichnisse würden unversionierte\n"
 "Dateien in diesen Verzeichnissen verloren gehen:\n"
 "%s"
 
 #: unpack-trees.c:85
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
 "%%sPlease move or remove them before you switch branches."
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
 "den Checkout entfernt werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor Sie Branches wechseln."
 
 #: unpack-trees.c:87
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by checkout:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "Checkout entfernt werden:\n"
 "%%s"
 
 #: unpack-trees.c:90
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be removed by merge:\n"
 "%%sPlease move or remove them before you merge."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Merge entfernt werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Merge entfernt werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor sie mergen."
 
 #: unpack-trees.c:92
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by merge:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "Merge entfernt werden:\n"
 "%%s"
 
 #: unpack-trees.c:95
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be removed by %s:\n"
 "%%sPlease move or remove them before you %s."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"%s entfernt werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den %s entfernt werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor sie %s ausführen."
 
 #: unpack-trees.c:97
 #, c-format
 msgid ""
 "The following untracked working tree files would be removed by %s:\n"
 "%%s"
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"%s entfernt werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den %s entfernt werden:\n"
 "%%s"
 
 #: unpack-trees.c:102
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by "
 "checkout:\n"
 "%%sPlease move or remove them before you switch branches."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Checkout überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Checkout überschrieben werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor Sie Branches wechseln."
 
 #: unpack-trees.c:104
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by "
 "checkout:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "Checkout überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:107
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
 "%%sPlease move or remove them before you merge."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Merge überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Merge überschrieben werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor Sie mergen."
 
 #: unpack-trees.c:109
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by merge:\n"
 "%%s"
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"Merge überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den Merge überschrieben werden:\n"
 "%%s"
 
 #: unpack-trees.c:112
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
 "%%sPlease move or remove them before you %s."
 msgstr ""
-"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
-"den\n"
-"%s überschrieben werden:\n"
+"Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch\n"
+"den %s überschrieben werden:\n"
 "%%sBitte verschieben oder entfernen Sie diese, bevor sie %s ausführen."
 
 #: unpack-trees.c:114
 #, c-format
 msgid ""
 "The following untracked working tree files would be overwritten by %s:\n"
 "%%s"
 msgstr ""
 "Die folgenden unversionierten Dateien im Arbeitsverzeichnis würden durch "
 "den\n"
 "%s überschrieben werden:\n"
 "%%s"
@@ -2472,27 +2491,27 @@ msgstr "eine 'file:' URL darf keine Portnummer enthalten"
 msgid "invalid characters in host name"
 msgstr "Hostname enthält ungültige Zeichen"
 
 #: urlmatch.c:244 urlmatch.c:255
 msgid "invalid port number"
 msgstr "ungültige Portnummer"
 
 #: urlmatch.c:322
 msgid "invalid '..' path segment"
 msgstr "ungültiges '..' Pfadsegment"
 
 #: worktree.c:282
-#, fuzzy, c-format
+#, c-format
 msgid "failed to read '%s'"
-msgstr "Fehler beim Lesen von %s"
+msgstr "Fehler beim Lesen von '%s'"
 
 #: wrapper.c:222 wrapper.c:392
 #, c-format
 msgid "could not open '%s' for reading and writing"
 msgstr "Konnte '%s' nicht zum Lesen und Schreiben öffnen."
 
 #: wrapper.c:224 wrapper.c:394 builtin/am.c:778
 #, c-format
 msgid "could not open '%s' for writing"
 msgstr "Konnte '%s' nicht zum Schreiben öffnen."
 
 #: wrapper.c:226 wrapper.c:396 builtin/am.c:324 builtin/am.c:771
@@ -2682,29 +2701,26 @@ msgstr ""
 "Ändern Sie nicht die obige Zeile.\n"
 "Alles unterhalb von ihr wird entfernt."
 
 #: wt-status.c:950
 msgid "You have unmerged paths."
 msgstr "Sie haben nicht zusammengeführte Pfade."
 
 #: wt-status.c:953
 msgid "  (fix conflicts and run \"git commit\")"
 msgstr " (beheben Sie die Konflikte und führen Sie \"git commit\" aus)"
 
 #: wt-status.c:955
-#, fuzzy
 msgid "  (use \"git merge --abort\" to abort the merge)"
-msgstr ""
-"  (benutzen Sie \"git am --abort\", um den ursprünglichen Branch "
-"wiederherzustellen)"
+msgstr "  (benutzen Sie \"git merge --abort\", um den Merge abzubrechen)"
 
 #: wt-status.c:960
 msgid "All conflicts fixed but you are still merging."
 msgstr "Alle Konflikte sind behoben, aber Sie sind immer noch beim Merge."
 
 #: wt-status.c:963
 msgid "  (use \"git commit\" to conclude merge)"
 msgstr "  (benutzen Sie \"git commit\", um den Merge abzuschließen)"
 
 #: wt-status.c:973
 msgid "You are in the middle of an am session."
 msgstr "Eine \"am\"-Sitzung ist im Gange."
@@ -2984,25 +3000,25 @@ msgstr ""
 #, c-format
 msgid "nothing to commit\n"
 msgstr "nichts zu committen\n"
 
 #: wt-status.c:1557
 #, c-format
 msgid "nothing to commit (use -u to show untracked files)\n"
 msgstr ""
 "nichts zu committen (benutzen Sie die Option -u, um unversionierte Dateien "
 "anzuzeigen)\n"
 
 #: wt-status.c:1561
-#, fuzzy, c-format
+#, c-format
 msgid "nothing to commit, working tree clean\n"
 msgstr "nichts zu committen, Arbeitsverzeichnis unverändert\n"
 
 #: wt-status.c:1668
 msgid "Initial commit on "
 msgstr "Initialer Commit auf "
 
 #: wt-status.c:1672
 msgid "HEAD (no branch)"
 msgstr "HEAD (kein Branch)"
 
 #: wt-status.c:1701
@@ -3161,25 +3177,25 @@ msgstr "Hinzufügen von Dateien fehlgeschlagen"
 #: builtin/add.c:336
 msgid "-A and -u are mutually incompatible"
 msgstr "Die Optionen -A und -u sind zueinander inkompatibel."
 
 #: builtin/add.c:343
 msgid "Option --ignore-missing can only be used together with --dry-run"
 msgstr ""
 "Die Option --ignore-missing kann nur zusammen mit --dry-run verwendet werden."
 
 #: builtin/add.c:352
 #, c-format
 msgid "--chmod param '%s' must be either -x or +x"
-msgstr ""
+msgstr "--chmod Parameter '%s' muss entweder -x oder +x sein"
 
 #: builtin/add.c:367
 #, c-format
 msgid "Nothing specified, nothing added.\n"
 msgstr "Nichts spezifiziert, nichts hinzugefügt.\n"
 
 #: builtin/add.c:368
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "Meinten Sie vielleicht 'git add .'?\n"
 
 #: builtin/add.c:373 builtin/check-ignore.c:172 builtin/checkout.c:279
@@ -4468,34 +4484,33 @@ msgstr "falsch benannten Branch '%s' umbenannt"
 #: builtin/branch.c:597
 #, c-format
 msgid "Branch renamed to %s, but HEAD is not updated!"
 msgstr "Branch umbenannt zu %s, aber HEAD ist nicht aktualisiert!"
 
 #: builtin/branch.c:604
 msgid "Branch is renamed, but update of config-file failed"
 msgstr ""
 "Branch ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist "
 "fehlgeschlagen."
 
 #: builtin/branch.c:620
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Please edit the description for the branch\n"
 "  %s\n"
 "Lines starting with '%c' will be stripped.\n"
 msgstr ""
-"\n"
-"Geben Sie eine Beschreibung für Tag\n"
+"Bitte ändern Sie die Beschreibung für den Branch\n"
 "  %s\n"
-"ein. Zeilen, die mit '%c' beginnen, werden ignoriert.\n"
+"Zeilen, die mit '%c' beginnen, werden entfernt.\n"
 
 #: builtin/branch.c:651
 msgid "Generic options"
 msgstr "Allgemeine Optionen"
 
 #: builtin/branch.c:653
 msgid "show hash and subject, give twice for upstream branch"
 msgstr "Hash und Betreff anzeigen; -vv: zusätzlich Upstream-Branch"
 
 #: builtin/branch.c:654
 msgid "suppress informational messages"
 msgstr "Informationsmeldungen unterdrücken"
@@ -6313,27 +6328,26 @@ msgstr "die angegebenen Dateien zusätzlich zum Commit vormerken"
 msgid "interactively add files"
 msgstr "interaktives Hinzufügen von Dateien"
 
 #: builtin/commit.c:1618
 msgid "interactively add changes"
 msgstr "interaktives Hinzufügen von Änderungen"
 
 #: builtin/commit.c:1619
 msgid "commit only specified files"
 msgstr "nur die angegebenen Dateien committen"
 
 #: builtin/commit.c:1620
-#, fuzzy
 msgid "bypass pre-commit and commit-msg hooks"
-msgstr "\"pre-commit hook\" umgehen"
+msgstr "Hooks pre-commit und commit-msg umgehen"
 
 #: builtin/commit.c:1621
 msgid "show what would be committed"
 msgstr "anzeigen, was committet werden würde"
 
 #: builtin/commit.c:1632
 msgid "amend previous commit"
 msgstr "vorherigen Commit ändern"
 
 #: builtin/commit.c:1633
 msgid "bypass post-rewrite hook"
 msgstr "\"post-rewrite hook\" umgehen"
@@ -6875,44 +6889,42 @@ msgstr "Refmap"
 
 #: builtin/fetch.c:131 builtin/pull.c:211
 msgid "specify fetch refmap"
 msgstr "Refmap für 'fetch' angeben"
 
 #: builtin/fetch.c:387
 msgid "Couldn't find remote ref HEAD"
 msgstr "Konnte Remote-Referenz von HEAD nicht finden."
 
 #: builtin/fetch.c:503
 #, c-format
 msgid "configuration fetch.output contains invalid value %s"
-msgstr ""
+msgstr "Konfiguration fetch.output enthält ungültigen Wert %s"
 
 #: builtin/fetch.c:592
 #, c-format
 msgid "object %s not found"
 msgstr "Objekt %s nicht gefunden"
 
 #: builtin/fetch.c:596
 msgid "[up to date]"
 msgstr "[aktuell]"
 
 #: builtin/fetch.c:609 builtin/fetch.c:689
 msgid "[rejected]"
 msgstr "[zurückgewiesen]"
 
 #: builtin/fetch.c:610
-#, fuzzy
 msgid "can't fetch in current branch"
-msgstr ""
-"! %-*s %-*s -> %s  (kann \"fetch\" im aktuellen Branch nicht ausführen)"
+msgstr "kann \"fetch\" im aktuellen Branch nicht ausführen"
 
 #: builtin/fetch.c:619
 msgid "[tag update]"
 msgstr "[Tag Aktualisierung]"
 
 #: builtin/fetch.c:620 builtin/fetch.c:653 builtin/fetch.c:669
 #: builtin/fetch.c:684
 msgid "unable to update local ref"
 msgstr "kann lokale Referenz nicht aktualisieren"
 
 #: builtin/fetch.c:639
 msgid "[new tag]"
@@ -6922,27 +6934,26 @@ msgstr "[neues Tag]"
 msgid "[new branch]"
 msgstr "[neuer Branch]"
 
 #: builtin/fetch.c:645
 msgid "[new ref]"
 msgstr "[neue Referenz]"
 
 #: builtin/fetch.c:684
 msgid "forced update"
 msgstr "Aktualisierung erzwungen"
 
 #: builtin/fetch.c:689
-#, fuzzy
 msgid "non-fast-forward"
-msgstr "(kein Vorspulen)"
+msgstr "kein Vorspulen"
 
 #: builtin/fetch.c:733
 #, c-format
 msgid "%s did not send all necessary objects\n"
 msgstr "%s hat nicht alle erforderlichen Objekte gesendet\n"
 
 #: builtin/fetch.c:753
 #, c-format
 msgid "reject %s because shallow roots are not allowed to be updated"
 msgstr ""
 "%s wurde zurückgewiesen, da Ursprungs-Commits von Repositoriesmit "
 "unvollständiger Historie (shallow) nicht aktualisiert werden dürfen."
@@ -7181,27 +7192,26 @@ msgstr "nur Konnektivität prüfen"
 msgid "enable more strict checking"
 msgstr "genauere Prüfung aktivieren"
 
 #: builtin/fsck.c:604
 msgid "write dangling objects in .git/lost-found"
 msgstr "unreferenzierte Objekte nach .git/lost-found schreiben"
 
 #: builtin/fsck.c:605 builtin/prune.c:107
 msgid "show progress"
 msgstr "Fortschrittsanzeige anzeigen"
 
 #: builtin/fsck.c:606
-#, fuzzy
 msgid "show verbose names for reachable objects"
-msgstr "unerreichbare Objekte anzeigen"
+msgstr "erweiterten Namen für erreichbare Objekte anzeigen"
 
 #: builtin/fsck.c:671
 msgid "Checking objects"
 msgstr "Prüfe Objekte"
 
 #: builtin/gc.c:25
 msgid "git gc [<options>]"
 msgstr "git gc [<Optionen>]"
 
 #: builtin/gc.c:72
 #, c-format
 msgid "Invalid %s: '%s'"
@@ -7748,27 +7758,27 @@ msgid "cannot open packfile '%s'"
 msgstr "Kann Paketdatei '%s' nicht öffnen"
 
 #: builtin/index-pack.c:333
 msgid "pack signature mismatch"
 msgstr "Paketsignatur stimmt nicht überein"
 
 #: builtin/index-pack.c:335
 #, c-format
 msgid "pack version %<PRIu32> unsupported"
 msgstr "Paketversion %<PRIu32> nicht unterstützt"
 
 #: builtin/index-pack.c:353
-#, fuzzy, c-format
+#, c-format
 msgid "pack has bad object at offset %<PRIuMAX>: %s"
-msgstr "Paket hat ein ungültiges Objekt bei Versatz %lu: %s"
+msgstr "Paket hat ein ungültiges Objekt bei Versatz %<PRIuMAX>: %s"
 
 #: builtin/index-pack.c:475
 #, c-format
 msgid "inflate returned %d"
 msgstr "Dekomprimierung gab %d zurück"
 
 #: builtin/index-pack.c:524
 msgid "offset value overflow for delta base object"
 msgstr "Wert für Versatz bei Differenzobjekt übergelaufen"
 
 #: builtin/index-pack.c:532
 msgid "delta base offset is out of bound"
@@ -7776,29 +7786,29 @@ msgstr ""
 "Wert für Versatz bei Differenzobjekt liegt außerhalb des gültigen Bereichs"
 
 #: builtin/index-pack.c:540
 #, c-format
 msgid "unknown object type %d"
 msgstr "Unbekannter Objekt-Typ %d"
 
 #: builtin/index-pack.c:571
 msgid "cannot pread pack file"
 msgstr "Kann Paketdatei %s nicht lesen"
 
 #: builtin/index-pack.c:573
-#, fuzzy, c-format
+#, c-format
 msgid "premature end of pack file, %<PRIuMAX> byte missing"
 msgid_plural "premature end of pack file, %<PRIuMAX> bytes missing"
-msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %lu Byte"
-msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %lu Bytes"
+msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %<PRIuMAX> Byte"
+msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %<PRIuMAX> Bytes"
 
 #: builtin/index-pack.c:599
 msgid "serious inflate inconsistency"
 msgstr "ernsthafte Inkonsistenz nach Dekomprimierung"
 
 #: builtin/index-pack.c:745 builtin/index-pack.c:751 builtin/index-pack.c:774
 #: builtin/index-pack.c:808 builtin/index-pack.c:817
 #, c-format
 msgid "SHA1 COLLISION FOUND WITH %s !"
 msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !"
 
 #: builtin/index-pack.c:748 builtin/pack-objects.c:164
@@ -8028,42 +8038,42 @@ msgstr "%s existiert bereits"
 
 #: builtin/init-db.c:344
 #, c-format
 msgid "unable to handle file type %d"
 msgstr "kann nicht mit Dateityp %d umgehen"
 
 #: builtin/init-db.c:347
 #, c-format
 msgid "unable to move %s to %s"
 msgstr "Konnte %s nicht nach %s verschieben"
 
 #: builtin/init-db.c:402
-#, fuzzy, c-format
+#, c-format
 msgid "Reinitialized existing shared Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Bestehendes verteiltes Git-Repository in %s%s neuinitialisiert\n"
 
 #: builtin/init-db.c:403
-#, fuzzy, c-format
+#, c-format
 msgid "Reinitialized existing Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Bestehendes Git-Repository in %s%s neuinitialisiert\n"
 
 #: builtin/init-db.c:407
-#, fuzzy, c-format
+#, c-format
 msgid "Initialized empty shared Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Leeres verteiltes Git-Repository in %s%s initialisiert\n"
 
 #: builtin/init-db.c:408
-#, fuzzy, c-format
+#, c-format
 msgid "Initialized empty Git repository in %s%s\n"
-msgstr "%s%s Git-Repository in %s%s\n"
+msgstr "Leeres Git-Repository in %s%s initialisiert\n"
 
 #: builtin/init-db.c:455
 msgid ""
 "git init [-q | --quiet] [--bare] [--template=<template-directory>] [--"
 "shared[=<permissions>]] [<directory>]"
 msgstr ""
 "git init [-q | --quiet] [--bare] [--template=<Vorlagenverzeichnis>] [--"
 "shared[=<Berechtigungen>]] [<Verzeichnis>]"
 
 #: builtin/init-db.c:478
 msgid "permissions"
 msgstr "Berechtigungen"
@@ -8862,40 +8872,39 @@ msgstr "Kein Remote-Repository für den aktuellen Branch."
 msgid "No default upstream defined for the current branch."
 msgstr ""
 "Es ist kein Standard-Upstream-Branch für den aktuellen Branch definiert."
 
 #: builtin/merge.c:913
 #, c-format
 msgid "No remote-tracking branch for %s from %s"
 msgstr "Kein Remote-Tracking-Branch für %s von %s"
 
 #: builtin/merge.c:960
 #, c-format
 msgid "Bad value '%s' in environment '%s'"
-msgstr ""
+msgstr "Fehlerhafter Wert '%s' in Umgebungsvariable '%s'"
 
 #: builtin/merge.c:1034
 #, c-format
 msgid "could not close '%s'"
 msgstr "Konnte '%s' nicht schließen"
 
 #: builtin/merge.c:1061
-#, fuzzy, c-format
+#, c-format
 msgid "not something we can merge in %s: %s"
-msgstr "%s - nichts was wir zusammenführen können"
+msgstr "nichts was wir in %s zusammenführen können: %s"
 
 #: builtin/merge.c:1095
-#, fuzzy
 msgid "not something we can merge"
-msgstr "%s - nichts was wir zusammenführen können"
+msgstr "nichts was wir zusammenführen können"
 
 #: builtin/merge.c:1162
 msgid "There is no merge to abort (MERGE_HEAD missing)."
 msgstr "Es gibt keinen Merge zum Abbrechen (MERGE_HEAD fehlt)"
 
 #: builtin/merge.c:1178
 msgid ""
 "You have not concluded your merge (MERGE_HEAD exists).\n"
 "Please, commit your changes before you merge."
 msgstr ""
 "Sie haben Ihren Merge nicht abgeschlossen (MERGE_HEAD existiert).\n"
 "Bitte committen Sie Ihre Änderungen, bevor Sie den Merge ausführen."
@@ -8958,47 +8967,45 @@ msgid "Commit %s does not have a GPG signature."
 msgstr "Commit %s hat keine GPG-Signatur."
 
 #: builtin/merge.c:1296
 #, c-format
 msgid "Commit %s has a good GPG signature by %s\n"
 msgstr "Commit %s hat eine gültige GPG-Signatur von %s\n"
 
 #: builtin/merge.c:1358
 msgid "refusing to merge unrelated histories"
 msgstr "Verweigere den Merge von nicht zusammenhängenden Historien."
 
 #: builtin/merge.c:1367
-#, fuzzy
 msgid "Already up-to-date."
-msgstr "Bereits aktuell!"
+msgstr "Bereits aktuell."
 
 #: builtin/merge.c:1382
 #, c-format
 msgid "Updating %s..%s\n"
 msgstr "Aktualisiere %s..%s\n"
 
 #: builtin/merge.c:1419
 #, c-format
 msgid "Trying really trivial in-index merge...\n"
 msgstr "Probiere wirklich trivialen \"in-index\"-Merge ...\n"
 
 #: builtin/merge.c:1426
 #, c-format
 msgid "Nope.\n"
 msgstr "Nein.\n"
 
 #: builtin/merge.c:1451
-#, fuzzy
 msgid "Already up-to-date. Yeeah!"
-msgstr "Bereits aktuell!"
+msgstr "Bereits aktuell."
 
 #: builtin/merge.c:1457
 msgid "Not possible to fast-forward, aborting."
 msgstr "Vorspulen nicht möglich, breche ab."
 
 #: builtin/merge.c:1480 builtin/merge.c:1559
 #, c-format
 msgid "Rewinding the tree to pristine...\n"
 msgstr "Rücklauf des Verzeichnisses bis zum Ursprung ...\n"
 
 #: builtin/merge.c:1484
 #, c-format
@@ -9362,25 +9369,25 @@ msgid "git notes remove [<object>]"
 msgstr "git notes remove [<Objekt>]"
 
 #: builtin/notes.c:84
 msgid "git notes prune [<options>]"
 msgstr "git notes prune [<Optionen>]"
 
 #: builtin/notes.c:89
 msgid "git notes get-ref"
 msgstr "git notes get-ref"
 
 #: builtin/notes.c:94
 msgid "Write/edit the notes for the following object:"
-msgstr ""
+msgstr "Schreiben/Bearbeiten der Notizen für das folgende Objekt:"
 
 #: builtin/notes.c:147
 #, c-format
 msgid "unable to start 'show' for object '%s'"
 msgstr "konnte 'show' für Objekt '%s' nicht starten"
 
 #: builtin/notes.c:151
 msgid "could not read 'show' output"
 msgstr "Konnte Ausgabe von 'show' nicht lesen."
 
 #: builtin/notes.c:159
 #, c-format
@@ -9504,27 +9511,27 @@ msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Keine Notizen für Quell-Objekt %s. Kopie nicht möglich."
 
 #: builtin/notes.c:587
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
 "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
 msgstr ""
 "Die Optionen -m/-F/-c/-C sind für den Unterbefehl 'edit' veraltet.\n"
 "Bitte benutzen Sie stattdessen 'git notes add -f -m/-F/-c/-C'.\n"
 
 #: builtin/notes.c:753
-#, fuzzy, c-format
+#, c-format
 msgid "unknown notes merge strategy %s"
-msgstr "Konnte Merge-Strategie '%s' nicht finden.\n"
+msgstr "unbekannte Merge-Strategie '%s' für Notizen"
 
 #: builtin/notes.c:769
 msgid "General options"
 msgstr "Allgemeine Optionen"
 
 #: builtin/notes.c:771
 msgid "Merge options"
 msgstr "Merge-Optionen"
 
 #: builtin/notes.c:773
 msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
@@ -9544,75 +9551,76 @@ msgstr ""
 "committet werden"
 
 #: builtin/notes.c:779
 msgid "Aborting notes merge resolution"
 msgstr "Konfliktauflösung beim Merge von Notizen abbrechen"
 
 #: builtin/notes.c:781
 msgid "abort notes merge"
 msgstr "Merge von Notizen abbrechen"
 
 #: builtin/notes.c:792
 msgid "cannot mix --commit, --abort or -s/--strategy"
-msgstr ""
+msgstr "Kann --commit, --abort oder -s/--strategy nicht kombinieren."
 
 #: builtin/notes.c:797
-#, fuzzy
 msgid "Must specify a notes ref to merge"
-msgstr "Sie müssen ein Repository angeben."
+msgstr "Sie müssen eine Notiz-Referenz zum Mergen angeben."
 
 #: builtin/notes.c:821
-#, fuzzy, c-format
+#, c-format
 msgid "Unknown -s/--strategy: %s"
-msgstr "Unbekannter Typ: %d"
+msgstr "Unbekannter Wert für -s/--strategy: %s"
 
 #: builtin/notes.c:858
 #, c-format
 msgid "A notes merge into %s is already in-progress at %s"
 msgstr "Ein Merge von Notizen nach %s ist bereits im Gange bei %s"
 
 #: builtin/notes.c:861
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to store link to current notes ref (%s)"
-msgstr "Fehler beim Finden des \"Tree\"-Objektes von %s."
+msgstr "Fehler beim Speichern der Verknüpfung zur aktuellen Notes-Referenz (%s)"
 
 #: builtin/notes.c:863
 #, c-format
 msgid ""
 "Automatic notes merge failed. Fix conflicts in %s and commit the result with "
 "'git notes merge --commit', or abort the merge with 'git notes merge --"
 "abort'.\n"
 msgstr ""
+"Automatisches Zusammenführen der Notizen fehlgeschlagen. Beheben Sie die\n"
+"Konflikte in %s und committen Sie das Ergebnis mit 'git notes merge --commit',\n"
+"oder brechen Sie den Merge mit 'git notes merge --abort' ab.\n"
 
 #: builtin/notes.c:885
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Objekt %s hat keine Notiz\n"
 
 #: builtin/notes.c:897
 msgid "attempt to remove non-existent note is not an error"
 msgstr "der Versuch, eine nicht existierende Notiz zu löschen, ist kein Fehler"
 
 #: builtin/notes.c:900
 msgid "read object names from the standard input"
 msgstr "Objektnamen von der Standard-Eingabe lesen"
 
 #: builtin/notes.c:938 builtin/prune.c:105 builtin/worktree.c:127
 msgid "do not remove, show only"
 msgstr "nicht löschen, nur anzeigen"
 
 #: builtin/notes.c:939
-#, fuzzy
 msgid "report pruned notes"
-msgstr "gelöschte Objekte melden"
+msgstr "gelöschte Notizen melden"
 
 #: builtin/notes.c:981
 msgid "notes-ref"
 msgstr "Notiz-Referenz"
 
 #: builtin/notes.c:982
 msgid "use notes from <notes-ref>"
 msgstr "Notizen von <Notiz-Referenz> verwenden"
 
 #: builtin/notes.c:1017 builtin/remote.c:1623
 #, c-format
 msgid "Unknown subcommand: %s"
@@ -9767,27 +9775,26 @@ msgstr "Objekte einschließen, die vom Index referenziert werden"
 msgid "output pack to stdout"
 msgstr "Paket in die Standard-Ausgabe schreiben"
 
 #: builtin/pack-objects.c:2695
 msgid "include tag objects that refer to objects to be packed"
 msgstr "Tag-Objekte einschließen, die auf gepackte Objekte referenzieren"
 
 #: builtin/pack-objects.c:2697
 msgid "keep unreachable objects"
 msgstr "nicht erreichbare Objekte behalten"
 
 #: builtin/pack-objects.c:2699
-#, fuzzy
 msgid "pack loose unreachable objects"
-msgstr "nicht erreichbare Objekte behalten"
+msgstr "nicht erreichbare lose Objekte packen"
 
 #: builtin/pack-objects.c:2700 parse-options.h:142
 msgid "time"
 msgstr "Zeit"
 
 #: builtin/pack-objects.c:2701
 msgid "unpack unreachable objects newer than <time>"
 msgstr "nicht erreichbare Objekte entpacken, die neuer als <Zeit> sind"
 
 #: builtin/pack-objects.c:2704
 msgid "create thin packs"
 msgstr "dünnere Pakete erzeugen"
@@ -9985,25 +9992,25 @@ msgstr ""
 #: builtin/pull.c:503
 #, c-format
 msgid ""
 "Your configuration specifies to merge with the ref '%s'\n"
 "from the remote, but no such ref was fetched."
 msgstr ""
 "Ihre Konfiguration gibt an, den Merge mit Referenz '%s'\n"
 "des Remote-Repositories durchzuführen, aber diese Referenz\n"
 "wurde nicht angefordert."
 
 #: builtin/pull.c:820
 msgid "ignoring --verify-signatures for rebase"
-msgstr ""
+msgstr "Ignoriere --verify-signatures für Rebase"
 
 #: builtin/pull.c:867
 msgid "--[no-]autostash option is only valid with --rebase."
 msgstr "--[no-]autostash ist nur mit --rebase zulässig."
 
 #: builtin/pull.c:875
 msgid "Updating an unborn branch with changes added to the index."
 msgstr ""
 "Aktualisiere einen ungeborenen Branch mit Änderungen, die zum Commit "
 "vorgemerkt sind."
 
 #: builtin/pull.c:903
@@ -10323,42 +10330,41 @@ msgid "push missing but relevant tags"
 msgstr "fehlende, aber relevante Tags versenden"
 
 #: builtin/push.c:543 builtin/send-pack.c:166
 msgid "GPG sign the push"
 msgstr "signiert \"push\" mit GPG"
 
 #: builtin/push.c:545 builtin/send-pack.c:170
 msgid "request atomic transaction on remote side"
 msgstr "Referenzen atomar versenden"
 
 #: builtin/push.c:546
 msgid "server-specific"
-msgstr ""
+msgstr "serverspezifisch"
 
 #: builtin/push.c:546
-#, fuzzy
 msgid "option to transmit"
-msgstr "nichts zu committen\n"
+msgstr "Optionen übertragen"
 
 #: builtin/push.c:560
 msgid "--delete is incompatible with --all, --mirror and --tags"
 msgstr "Die Option --delete ist inkompatibel mit --all, --mirror und --tags."
 
 #: builtin/push.c:562
 msgid "--delete doesn't make sense without any refs"
 msgstr "Die Option --delete kann nur mit Referenzen verwendet werden."
 
 #: builtin/push.c:579
 msgid "push options must not have new line characters"
-msgstr ""
+msgstr "Push-Optionen dürfen keine Zeilenvorschubzeichen haben"
 
 #: builtin/read-tree.c:37
 msgid ""
 "git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>) "
 "[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
 "index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"
 msgstr ""
 "git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<Präfix>) "
 "[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--"
 "index-output=<Datei>] (--empty | <Commit-Referenz1> [<Commit-Referenz2> "
 "[<Commit-Referenz3>]])"
 
@@ -10689,42 +10695,42 @@ msgstr " ???"
 
 #: builtin/remote.c:955
 #, c-format
 msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
 msgstr "ungültiges branch.%s.merge; kann Rebase nicht auf > 1 Branch ausführen"
 
 #: builtin/remote.c:963
 #, c-format
 msgid "rebases interactively onto remote %s"
 msgstr "interaktiver Rebase auf Remote-Branch %s"
 
 #: builtin/remote.c:964
-#, fuzzy, c-format
+#, c-format
 msgid "rebases onto remote %s"
-msgstr "interaktiver Rebase auf Remote-Branch %s"
+msgstr "Rebase auf Remote-Branch %s"
 
 #: builtin/remote.c:967
 #, c-format
 msgid " merges with remote %s"
 msgstr " führt mit Remote-Branch %s zusammen"
 
 #: builtin/remote.c:970
 #, c-format
 msgid "merges with remote %s"
 msgstr "führt mit Remote-Branch %s zusammen"
 
 #: builtin/remote.c:973
-#, fuzzy, c-format
+#, c-format
 msgid "%-*s    and with remote %s\n"
-msgstr "    und mit Remote-Branch"
+msgstr "%-*s    und mit Remote-Branch %s\n"
 
 #: builtin/remote.c:1016
 msgid "create"
 msgstr "erstellt"
 
 #: builtin/remote.c:1019
 msgid "delete"
 msgstr "gelöscht"
 
 #: builtin/remote.c:1023
 msgid "up to date"
 msgstr "aktuell"
@@ -10779,32 +10785,30 @@ msgstr "(keine URL)"
 #. the one in "  Fetch URL: %s" translation
 #: builtin/remote.c:1154 builtin/remote.c:1156
 #, c-format
 msgid "  Push  URL: %s"
 msgstr "  URL zum Versenden: %s"
 
 #: builtin/remote.c:1158 builtin/remote.c:1160 builtin/remote.c:1162
 #, c-format
 msgid "  HEAD branch: %s"
 msgstr "  Hauptbranch: %s"
 
 #: builtin/remote.c:1158
-#, fuzzy
 msgid "(not queried)"
-msgstr " (Zustand nicht abgefragt)"
+msgstr "(nicht abgefragt)"
 
 #: builtin/remote.c:1160
-#, fuzzy
 msgid "(unknown)"
-msgstr "unbekannt:"
+msgstr "(unbekannt)"
 
 #: builtin/remote.c:1164
 #, c-format
 msgid ""
 "  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
 msgstr ""
 "  Hauptbranch (externer HEAD ist mehrdeutig, könnte einer der folgenden "
 "sein):\n"
 
 #: builtin/remote.c:1176
 #, c-format
 msgid "  Remote branch:%s"
@@ -10997,27 +11001,26 @@ msgstr "--local an git-pack-objects übergeben"
 msgid "write bitmap index"
 msgstr "Bitmap-Index schreiben"
 
 #: builtin/repack.c:177
 msgid "approxidate"
 msgstr "Datumsangabe"
 
 #: builtin/repack.c:178
 msgid "with -A, do not loosen objects older than this"
 msgstr "mit -A, keine Objekte älter als dieses Datum löschen"
 
 #: builtin/repack.c:180
-#, fuzzy
 msgid "with -a, repack unreachable objects"
-msgstr "nicht erreichbare Objekte behalten"
+msgstr "mit -a, nicht erreichbare Objekte neu packen"
 
 #: builtin/repack.c:182
 msgid "size of the window used for delta compression"
 msgstr "Größe des Fensters für die Delta-Kompression"
 
 #: builtin/repack.c:183 builtin/repack.c:187
 msgid "bytes"
 msgstr "Bytes"
 
 #: builtin/repack.c:184
 msgid "same as the above, but limit memory size instead of entries count"
 msgstr ""
@@ -11033,27 +11036,26 @@ msgid "maximum size of each packfile"
 msgstr "maximale Größe für jede Paketdatei"
 
 #: builtin/repack.c:190
 msgid "repack objects in packs marked with .keep"
 msgstr ""
 "Objekte umpacken, die sich in mit .keep markierten Pack-Dateien befinden"
 
 #: builtin/repack.c:200
 msgid "cannot delete packs in a precious-objects repo"
 msgstr "kann Pack-Dateien in precious-objects Repository nicht löschen"
 
 #: builtin/repack.c:204
-#, fuzzy
 msgid "--keep-unreachable and -A are incompatible"
-msgstr "--column und -n sind inkompatibel"
+msgstr "--keep-unreachable und -A sind inkompatibel"
 
 #: builtin/repack.c:391 builtin/worktree.c:115
 #, c-format
 msgid "failed to remove '%s'"
 msgstr "Fehler beim Löschen von '%s'"
 
 #: builtin/replace.c:19
 msgid "git replace [-f] <object> <replacement>"
 msgstr "git replace [-f] <Objekt> <Ersetzung>"
 
 #: builtin/replace.c:20
 msgid "git replace [-f] --edit <object>"
@@ -11821,32 +11823,32 @@ msgstr "Meinten Sie vielleicht 'update --init'?"
 
 #: builtin/submodule--helper.c:641
 #, c-format
 msgid "Skipping unmerged submodule %s"
 msgstr "Überspringe nicht zusammengeführtes Submodul %s"
 
 #: builtin/submodule--helper.c:662
 #, c-format
 msgid "Skipping submodule '%s'"
 msgstr "Überspringe Submodul '%s'"
 
 #: builtin/submodule--helper.c:792
-#, fuzzy, c-format
+#, c-format
 msgid "Failed to clone '%s'. Retry scheduled"
-msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'"
+msgstr "Fehler beim Klonen von '%s'. Weiterer Versuch geplant"
 
 #: builtin/submodule--helper.c:803
 #, c-format
 msgid "Failed to clone '%s' a second time, aborting"
-msgstr ""
+msgstr "Zweiter Versuch '%s' zu klonen fehlgeschlagen, breche ab."
 
 #: builtin/submodule--helper.c:824
 msgid "path into the working tree"
 msgstr "Pfad zum Arbeitsverzeichnis"
 
 #: builtin/submodule--helper.c:827
 msgid "path into the working tree, across nested submodule boundaries"
 msgstr ""
 "Pfad zum Arbeitsverzeichnis, über verschachtelte Submodul-Grenzen hinweg"
 
 #: builtin/submodule--helper.c:831
 msgid "rebase, merge, checkout or none"
@@ -11857,43 +11859,47 @@ msgid "Create a shallow clone truncated to the specified number of revisions"
 msgstr ""
 "Erstellung eines Klons mit unvollständiger Historie (shallow), abgeschnitten "
 "bei\n"
 "der angegebenen Anzahl von Commits."
 
 #: builtin/submodule--helper.c:838
 msgid "parallel jobs"
 msgstr "Parallele Ausführungen"
 
 #: builtin/submodule--helper.c:840
 msgid "whether the initial clone should follow the shallow recommendation"
 msgstr ""
+"ob das initiale Klonen den Empfehlungen für eine unvollständige\n"
+"Historie (shallow) folgen soll"
 
 #: builtin/submodule--helper.c:841
 msgid "don't print cloning progress"
 msgstr "keine Fortschrittsanzeige beim Klonen"
 
 #: builtin/submodule--helper.c:846
 msgid "git submodule--helper update_clone [--prefix=<path>] [<path>...]"
 msgstr "git submodule--helper update_clone [--prefix=<Pfad>] [<Pfad>...]"
 
 #: builtin/submodule--helper.c:856
 msgid "bad value for update parameter"
 msgstr "Fehlerhafter Wert für --update Parameter"
 
 #: builtin/submodule--helper.c:927
 #, c-format
 msgid ""
 "Submodule (%s) branch configured to inherit branch from superproject, but "
 "the superproject is not on any branch"
 msgstr ""
+"Branch von Submodul (%s) ist konfiguriert, den Branch des Hauptprojektes\n"
+"zu erben, aber das Hauptprojekt befindet sich auf keinem Branch."
 
 #: builtin/submodule--helper.c:977
 msgid "submodule--helper subcommand must be called with a subcommand"
 msgstr "submodule--helper muss mit einem Unterbefehl aufgerufen werden"
 
 #: builtin/submodule--helper.c:984
 #, c-format
 msgid "'%s' is not a valid submodule--helper subcommand"
 msgstr "'%s' ist kein gültiger Unterbefehl von submodule--helper"
 
 #: builtin/symbolic-ref.c:7
 msgid "git symbolic-ref [<options>] <name> [<ref>]"
@@ -12406,36 +12412,34 @@ msgstr "git verify-tag [-v | --verbose] <Tag>..."
 msgid "print tag contents"
 msgstr "Tag-Inhalte ausgeben"
 
 #: builtin/worktree.c:15
 msgid "git worktree add [<options>] <path> [<branch>]"
 msgstr "git worktree add [<Optionen>] <Pfad> [<Branch>]"
 
 #: builtin/worktree.c:16
 msgid "git worktree list [<options>]"
 msgstr "git worktree list [<Optionen>]"
 
 #: builtin/worktree.c:17
-#, fuzzy
 msgid "git worktree lock [<options>] <path>"
-msgstr "git worktree list [<Optionen>]"
+msgstr "git worktree lock [<Optionen>] <Pfad>"
 
 #: builtin/worktree.c:18
 msgid "git worktree prune [<options>]"
 msgstr "git worktree prune [<Optionen>]"
 
 #: builtin/worktree.c:19
-#, fuzzy
 msgid "git worktree unlock <path>"
-msgstr "git worktree prune [<Optionen>]"
+msgstr "git worktree unlock <Pfad>"
 
 #: builtin/worktree.c:42
 #, c-format
 msgid "Removing worktrees/%s: not a valid directory"
 msgstr "Lösche worktrees/%s: kein gültiges Verzeichnis"
 
 #: builtin/worktree.c:48
 #, c-format
 msgid "Removing worktrees/%s: gitdir file does not exist"
 msgstr "Lösche worktrees/%s: gitdir-Datei existiert nicht"
 
 #: builtin/worktree.c:53
@@ -12483,86 +12487,85 @@ msgid "create or reset a branch"
 msgstr "Branch erstellen oder umsetzen"
 
 #: builtin/worktree.c:329
 msgid "populate the new working tree"
 msgstr "das neue Arbeitsverzeichnis auschecken"
 
 #: builtin/worktree.c:337
 msgid "-b, -B, and --detach are mutually exclusive"
 msgstr "-b, -B und --detach schließen sich gegenseitig aus"
 
 #: builtin/worktree.c:470
 msgid "reason for locking"
-msgstr ""
+msgstr "Sperrgrund"
 
 #: builtin/worktree.c:482 builtin/worktree.c:515
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is not a working tree"
-msgstr "'%s' ist kein Commit"
+msgstr "'%s' ist kein Arbeitsverzeichnis"
 
 #: builtin/worktree.c:484 builtin/worktree.c:517
 msgid "The main working tree cannot be locked or unlocked"
-msgstr ""
+msgstr "Das Hauptarbeitsverzeichnis kann nicht gesperrt oder entsperrt werden."
 
 #: builtin/worktree.c:489
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is already locked, reason: %s"
-msgstr "'%s' ist bereits in '%s' ausgecheckt"
+msgstr "'%s' ist bereits gesperrt, Grund: %s"
 
 #: builtin/worktree.c:491
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is already locked"
-msgstr "'%s' ist bereits in '%s' ausgecheckt"
+msgstr "'%s' ist bereits gesperrt"
 
 #: builtin/worktree.c:519
-#, fuzzy, c-format
+#, c-format
 msgid "'%s' is not locked"
-msgstr "'%s' ist kein Commit"
+msgstr "'%s' ist nicht gesperrt"
 
 #: builtin/write-tree.c:13
 msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
 msgstr "git write-tree [--missing-ok] [--prefix=<Präfix>/]"
 
 #: builtin/write-tree.c:26
 msgid "<prefix>/"
 msgstr "<Präfix>/"
 
 #: builtin/write-tree.c:27
 msgid "write tree object for a subdirectory <prefix>"
 msgstr "das \"Tree\"-Objekt für ein Unterverzeichnis <Präfix> schreiben"
 
 #: builtin/write-tree.c:30
 msgid "only useful for debugging"
 msgstr "nur nützlich für Fehlersuche"
 
 #: upload-pack.c:20
-#, fuzzy
 msgid "git upload-pack [<options>] <dir>"
-msgstr "git repack [<Optionen>]"
+msgstr "git upload-pack [<Optionen>] <Verzeichnis>"
 
 #: upload-pack.c:837
 msgid "quit after a single request/response exchange"
-msgstr ""
+msgstr "nach einem einzigen Request/Response-Austausch beenden"
 
 #: upload-pack.c:839
 msgid "exit immediately after initial ref advertisement"
-msgstr ""
+msgstr "direkt nach der initialen Angabe der Commits beenden"
 
 #: upload-pack.c:841
 msgid "do not try <directory>/.git/ if <directory> is no Git directory"
-msgstr ""
+msgstr "kein Versuch in <Verzeichnis>/.git/ wenn <Verzeichnis> kein Git-Verzeichnis ist"
 
 #: upload-pack.c:843
 msgid "interrupt transfer after <n> seconds of inactivity"
-msgstr ""
+msgstr "Übertragung nach <n> Sekunden Inaktivität unterbrechen"
 
 #: credential-cache--daemon.c:271
 msgid "print debugging messages to stderr"
 msgstr "Meldungen zur Fehlersuche in Standard-Fehlerausgabe ausgeben"
 
 #: git.c:14
 msgid ""
 "'git help -a' and 'git help -g' list available subcommands and some\n"
 "concept guides. See 'git help <command>' or 'git help <concept>'\n"
 "to read about a specific subcommand or concept."
 msgstr ""
 "'git help -a' und 'git help -g' listet verfügbare Unterbefehle und\n"
@@ -12759,27 +12762,27 @@ msgstr "Ungültiger HEAD - merkwürdige symbolische Referenz"
 
 #: git-bisect.sh:233
 #, sh-format
 msgid "Bad bisect_write argument: $state"
 msgstr "Ungültiges \"bisect_write\" Argument: $state"
 
 #: git-bisect.sh:262
 #, sh-format
 msgid "Bad rev input: $arg"
 msgstr "Ungültige Referenz-Eingabe: $arg"
 
 #: git-bisect.sh:281
-#, fuzzy, sh-format
+#, sh-format
 msgid "Bad rev input: $bisected_head"
-msgstr "Ungültige Referenz-Eingabe: $arg"
+msgstr "Ungültige Referenz-Eingabe: $bisected_head"
 
 #: git-bisect.sh:290
 #, sh-format
 msgid "Bad rev input: $rev"
 msgstr "Ungültige Referenz-Eingabe: $rev"
 
 #: git-bisect.sh:299
 #, sh-format
 msgid "'git bisect $TERM_BAD' can take only one argument."
 msgstr "'git bisect $TERM_BAD' kann nur ein Argument entgegennehmen."
 
 #: git-bisect.sh:322
@@ -12911,65 +12914,62 @@ msgid "no terms defined"
 msgstr "Keine Begriffe definiert."
 
 #: git-bisect.sh:653
 #, sh-format
 msgid ""
 "invalid argument $arg for 'git bisect terms'.\n"
 "Supported options are: --term-good|--term-old and --term-bad|--term-new."
 msgstr ""
 "Ungültiges Argument $arg für 'git bisect terms'.\n"
 "Unterstützte Optionen sind: --term-good|--term-old und --term-bad|--term-new."
 
 #: git-merge-octopus.sh:46
-#, fuzzy
 msgid ""
 "Error: Your local changes to the following files would be overwritten by "
 "merge"
 msgstr ""
-"Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
-"überschrieben werden:\n"
-"%%s"
+"Fehler Ihre lokalen Änderungen in den folgenden Dateien würden durch den Merge\n"
+"überschrieben werden"
 
 #: git-merge-octopus.sh:61
 msgid "Automated merge did not work."
-msgstr ""
+msgstr "Automatischer Merge hat nicht funktioniert."
 
 #: git-merge-octopus.sh:62
-#, fuzzy
 msgid "Should not be doing an Octopus."
-msgstr "Konnte Ausgabe nicht umleiten."
+msgstr "Sollte keinen Octopus-Merge ausführen."
 
 #: git-merge-octopus.sh:73
 #, sh-format
 msgid "Unable to find common commit with $pretty_name"
-msgstr ""
+msgstr "Konnte keinen gemeinsamen Commit mit $pretty_name finden."
 
 #: git-merge-octopus.sh:77
-#, fuzzy, sh-format
+#, sh-format
 msgid "Already up-to-date with $pretty_name"
-msgstr "Bereits aktuell!"
+msgstr "Bereits aktuell mit $pretty_name"
 
 #: git-merge-octopus.sh:89
-#, fuzzy, sh-format
+#, sh-format
 msgid "Fast-forwarding to: $pretty_name"
-msgstr "$branch_name zu $onto_name vorgespult."
+msgstr "Spule vor zu: $pretty_name"
 
 #: git-merge-octopus.sh:97
 #, sh-format
 msgid "Trying simple merge with $pretty_name"
-msgstr ""
+msgstr "Versuche einfachen Merge mit $pretty_name"
 
 #: git-merge-octopus.sh:102
 msgid "Simple merge did not work, trying automatic merge."
-msgstr ""
+msgstr "Einfacher Merge hat nicht funktioniert, versuche automatischen Merge."
 
 #: git-rebase.sh:56
 msgid ""
 "When you have resolved this problem, run \"git rebase --continue\".\n"
 "If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
 "To check out the original branch and stop rebasing, run \"git rebase --abort"
 "\"."
 msgstr ""
 "Wenn Sie das Problem aufgelöst haben, führen Sie \"git rebase --continue\" "
 "aus.\n"
 "Falls Sie diesen Patch auslassen möchten, führen Sie stattdessen \"git "
 "rebase --skip\" aus.\n"
@@ -13175,25 +13175,25 @@ msgstr "Keine lokalen Änderungen zum Speichern"
 
 #: git-stash.sh:263
 msgid "Cannot initialize stash"
 msgstr "Kann \"stash\" nicht initialisieren"
 
 #: git-stash.sh:267
 msgid "Cannot save the current status"
 msgstr "Kann den aktuellen Status nicht speichern"
 
 #: git-stash.sh:268
 #, sh-format
 msgid "Saved working directory and index state $stash_msg"
-msgstr ""
+msgstr "Speicherte Arbeitsverzeichnis und Index-Status $stash_msg"
 
 #: git-stash.sh:285
 msgid "Cannot remove worktree changes"
 msgstr "Kann Änderungen im Arbeitsverzeichnis nicht löschen"
 
 #: git-stash.sh:404
 #, sh-format
 msgid "unknown option: $opt"
 msgstr "unbekannte Option: $opt"
 
 #: git-stash.sh:414
 msgid "No stash found."
@@ -13236,25 +13236,25 @@ msgid "Could not save index tree"
 msgstr "Konnte Index-Verzeichnis nicht speichern"
 
 #: git-stash.sh:522
 msgid "Cannot unstage modified files"
 msgstr "Kann geänderte Dateien nicht aus dem Index entfernen"
 
 #: git-stash.sh:537
 msgid "Index was not unstashed."
 msgstr "Index wurde nicht aus dem Stash zurückgeladen."
 
 #: git-stash.sh:551
 msgid "The stash is kept in case you need it again."
-msgstr ""
+msgstr "Der Stash wird behalten, im Falle Sie benötigen diesen nochmal."
 
 #: git-stash.sh:560
 #, sh-format
 msgid "Dropped ${REV} ($s)"
 msgstr "Gelöscht ${REV} ($s)"
 
 #: git-stash.sh:561
 #, sh-format
 msgid "${REV}: Could not drop stash entry"
 msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen"
 
 #: git-stash.sh:569
@@ -13310,24 +13310,29 @@ msgstr ""
 "Repositories:"
 
 #: git-submodule.sh:244
 #, sh-format
 msgid ""
 "If you want to reuse this local git directory instead of cloning again from\n"
 "  $realrepo\n"
 "use the '--force' option. If the local git directory is not the correct "
 "repo\n"
 "or you are unsure what this means choose another name with the '--name' "
 "option."
 msgstr ""
+"Wenn Sie das lokale Git-Verzeichnis wiederverwenden wollen, anstatt erneut von\n"
+"  $realrepo\n"
+"zu klonen, benutzen Sie die Option '--force'. Wenn das lokale Git-Verzeichnis\n"
+"nicht das korrekte Repository ist oder Sie unsicher sind, was das bedeutet,\n"
+"wählen Sie einen anderen Namen mit der Option '--name'."
 
 #: git-submodule.sh:250
 #, sh-format
 msgid "Reactivating local git directory for submodule '$sm_name'."
 msgstr "Reaktiviere lokales Git-Verzeichnis für Submodul '$sm_name'."
 
 #: git-submodule.sh:262
 #, sh-format
 msgid "Unable to checkout submodule '$sm_path'"
 msgstr "Kann Submodul '$sm_path' nicht auschecken"
 
 #: git-submodule.sh:267
@@ -13354,33 +13359,32 @@ msgstr "Stoppe bei '$displaypath'; Skript gab nicht-Null Status zurück."
 #, sh-format
 msgid "pathspec and --all are incompatible"
 msgstr "Pfadspezifikationen und --all sind inkompatibel."
 
 #: git-submodule.sh:419
 #, sh-format
 msgid "Use '--all' if you really want to deinitialize all submodules"
 msgstr ""
 "Verwenden Sie '--all', wenn Sie wirklich alle Submodule deinitialisieren\n"
 "möchten."
 
 #: git-submodule.sh:439
-#, fuzzy, sh-format
+#, sh-format
 msgid ""
 "Submodule work tree '$displaypath' contains a .git directory\n"
 "(use 'rm -rf' if you really want to remove it including all of its history)"
 msgstr ""
-"Submodul '%s' (oder ein geschachteltes Submodul hiervon) verwendet\n"
-"ein .git-Verzeichnis (benutzen Sie 'rm -rf' wenn Sie dieses wirklich "
-"mitsamt\n"
-"seiner Historie löschen möchten)"
+"Arbeitsverzeichnis von Submodul in '$displaypath' enthält ein .git-Verzeichnis\n"
+"(benutzen Sie 'rm -rf' wenn Sie dieses wirklich mitsamt seiner Historie löschen\n"
+"möchten)"
 
 #: git-submodule.sh:447
 #, sh-format
 msgid ""
 "Submodule work tree '$displaypath' contains local modifications; use '-f' to "
 "discard them"
 msgstr ""
 "Arbeitsverzeichnis von Submodul in '$displaypath' enthält lokale Änderungen; "
 "verwenden Sie '-f', um diese zu verwerfen"
 
 #: git-submodule.sh:450
 #, sh-format
@@ -13408,41 +13412,45 @@ msgstr ""
 
 #: git-submodule.sh:612
 #, sh-format
 msgid "Unable to find current revision in submodule path '$displaypath'"
 msgstr "Konnte aktuellen Commit in Submodul-Pfad '$displaypath' nicht finden."
 
 #: git-submodule.sh:622
 #, sh-format
 msgid "Unable to fetch in submodule path '$sm_path'"
 msgstr "Konnte \"fetch\" in Submodul-Pfad '$sm_path' nicht ausführen"
 
 #: git-submodule.sh:627
-#, fuzzy, sh-format
+#, sh-format
 msgid ""
 "Unable to find current ${remote_name}/${branch} revision in submodule path "
 "'$sm_path'"
-msgstr "Konnte aktuellen Commit in Submodul-Pfad '$displaypath' nicht finden."
+msgstr ""
+"Konnte aktuellen Commit von ${remote_name}/${branch} in Submodul-Pfad\n"
+"'$sm_path' nicht finden."
 
 #: git-submodule.sh:645
 #, sh-format
 msgid "Unable to fetch in submodule path '$displaypath'"
 msgstr "Konnte \"fetch\" in Submodul-Pfad '$displaypath' nicht ausführen"
 
 #: git-submodule.sh:651
 #, sh-format
 msgid ""
 "Fetched in submodule path '$displaypath', but it did not contain $sha1. "
 "Direct fetching of that commit failed."
 msgstr ""
+"\"fetch\" in Submodul-Pfad '$displaypath' ausgeführt, aber $sha1 nicht\n"
+"enthalten. Direktes Anfordern dieses Commits ist fehlgeschlagen."
 
 #: git-submodule.sh:658
 #, sh-format
 msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
 msgstr "Konnte '$sha1' in Submodul-Pfad '$displaypath' nicht auschecken."
 
 #: git-submodule.sh:659
 #, sh-format
 msgid "Submodule path '$displaypath': checked out '$sha1'"
 msgstr "Submodul-Pfad: '$displaypath': '$sha1' ausgecheckt"
 
 #: git-submodule.sh:663
@@ -13521,420 +13529,471 @@ msgstr "Fehler bei Rekursion in Submodul-Pfad '$sm_path'"
 #, sh-format
 msgid "Synchronizing submodule url for '$displaypath'"
 msgstr "Synchronisiere Submodul-URL für '$displaypath'"
 
 #: git-parse-remote.sh:89
 #, sh-format
 msgid "See git-${cmd}(1) for details."
 msgstr "Siehe git-${cmd}(1) für weitere Details."
 
 #: git-rebase--interactive.sh:131
 #, sh-format
 msgid "Rebasing ($new_count/$total)"
-msgstr ""
+msgstr "Führe Rebase aus ($new_count/$total)"
 
 #: git-rebase--interactive.sh:147
 msgid ""
 "\n"
 "Commands:\n"
 " p, pick = use commit\n"
 " r, reword = use commit, but edit the commit message\n"
 " e, edit = use commit, but stop for amending\n"
 " s, squash = use commit, but meld into previous commit\n"
 " f, fixup = like \"squash\", but discard this commit's log message\n"
 " x, exec = run command (the rest of the line) using shell\n"
 " d, drop = remove commit\n"
 "\n"
 "These lines can be re-ordered; they are executed from top to bottom.\n"
 msgstr ""
+"\n"
+"Befehle:\n"
+" p, pick = Commit verwenden\n"
+" r, reword = Commit verwenden, aber Commit-Beschreibung bearbeiten\n"
+" e, edit = Commit verwenden, aber zum Nachbessern anhalten\n"
+" s, squash = Commit verwenden, aber mit vorherigem Commit vereinen\n"
+" f, fixup = wie \"squash\", aber die Log-Nachricht des Commits verwerden\n"
+" x, exec = Befehl (Rest der Zeile) mittels Shell ausführen\n"
+" d, drop = Commit entfernen\n"
+"\n"
+"Diese Zeilen können umsortiert werden; Sie werden von oben nach unten\n"
+"ausgeführt.\n"
 
 #: git-rebase--interactive.sh:162
 msgid ""
 "\n"
 "Do not remove any line. Use 'drop' explicitly to remove a commit.\n"
 msgstr ""
+"\n"
+"Keine Zeile entfernen. Benutzen Sie 'drop', um explizit einen Commit zu\n"
+"entfernen.\n"
 
 #: git-rebase--interactive.sh:166
 msgid ""
 "\n"
 "If you remove a line here THAT COMMIT WILL BE LOST.\n"
-msgstr ""
+msgstr "\nWenn Sie hier eine Zeile entfernen, wird DIESER COMMIT VERLOREN GEHEN.\n"
 
 #: git-rebase--interactive.sh:202
 #, sh-format
 msgid ""
 "You can amend the commit now, with\n"
 "\n"
 "\tgit commit --amend $gpg_sign_opt_quoted\n"
 "\n"
 "Once you are satisfied with your changes, run\n"
 "\n"
 "\tgit rebase --continue"
 msgstr ""
+"Sie können den Commit nun nachbessern mit:\n"
+"\n"
+"\tgit commit --amend $gpg_sign_opt_quoted\n"
+"\n"
+"Sobald Sie mit Ihren Änderungen zufrieden sind, führen Sie aus:\n"
+"\n"
+"\tgit rebase --continue"
 
 #: git-rebase--interactive.sh:227
 #, sh-format
 msgid "$sha1: not a commit that can be picked"
-msgstr ""
+msgstr "$sha1: kein Commit der gepickt werden kann"
 
 #: git-rebase--interactive.sh:266
-#, fuzzy, sh-format
+#, sh-format
 msgid "Invalid commit name: $sha1"
-msgstr "Ungültiger Commit: %s"
+msgstr "Ungültiger Commit-Name: $sha1"
 
 #: git-rebase--interactive.sh:308
-#, fuzzy
 msgid "Cannot write current commit's replacement sha1"
-msgstr "Kann den aktuellen Zustand des Arbeitsverzeichnisses nicht speichern"
+msgstr "Kann ersetzenden SHA-1 des aktuellen Commits nicht schreiben"
 
 #: git-rebase--interactive.sh:360
-#, fuzzy, sh-format
+#, sh-format
 msgid "Fast-forward to $sha1"
-msgstr "vorspulbar"
+msgstr "Spule vor zu $sha1"
 
 #: git-rebase--interactive.sh:362
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot fast-forward to $sha1"
-msgstr "Kann $stash_sha1 nicht speichern."
+msgstr "Kann nicht zu $sha1 vorspulen"
 
 #: git-rebase--interactive.sh:371
 #, sh-format
 msgid "Cannot move HEAD to $first_parent"
-msgstr ""
+msgstr "Kann HEAD nicht auf $first_parent setzen"
 
 #: git-rebase--interactive.sh:376
 #, sh-format
 msgid "Refusing to squash a merge: $sha1"
-msgstr ""
+msgstr "\"squash\" eines Merges ($sha1) zurückgewiesen."
 
 #: git-rebase--interactive.sh:390
-#, fuzzy, sh-format
+#, sh-format
 msgid "Error redoing merge $sha1"
-msgstr "Fehler beim Erzeugen der \"Tree\"-Objekte"
+msgstr "Fehler beim Wiederholen des Merges von $sha1"
 
 #: git-rebase--interactive.sh:398
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not pick $sha1"
-msgstr "Konnte %s nicht öffnen"
+msgstr "Konnte $sha1 nicht picken"
 
 #: git-rebase--interactive.sh:407
-#, fuzzy, sh-format
+#, sh-format
 msgid "This is the commit message #${n}:"
-msgstr "Commit-Beschreibung bearbeiten"
+msgstr "Das ist Commit-Beschreibung #${n}:"
 
 #: git-rebase--interactive.sh:412
-#, fuzzy, sh-format
+#, sh-format
 msgid "The commit message #${n} will be skipped:"
-msgstr "Commit-Beschreibung bearbeiten"
+msgstr "Commit-Beschreibung #${n} wird ausgelassen:"
 
 #: git-rebase--interactive.sh:423
 #, sh-format
 msgid "This is a combination of $count commit."
 msgid_plural "This is a combination of $count commits."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Das ist eine Kombination aus $count Commit."
+msgstr[1] "Das ist eine Kombination aus $count Commits."
 
 #: git-rebase--interactive.sh:431
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot write $fixup_msg"
-msgstr "Kann nicht überschreiben"
+msgstr "Kann $fixup_msg nicht schreiben"
 
 #: git-rebase--interactive.sh:434
 msgid "This is a combination of 2 commits."
-msgstr ""
+msgstr "Das ist eine Kombination aus 2 Commits."
 
 #: git-rebase--interactive.sh:435
-#, fuzzy
 msgid "This is the 1st commit message:"
-msgstr "Commit-Beschreibung bearbeiten"
+msgstr "Das ist die erste Commit-Beschreibung:"
 
 #: git-rebase--interactive.sh:475 git-rebase--interactive.sh:518
 #: git-rebase--interactive.sh:521
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not apply $sha1... $rest"
-msgstr "Konnte %s... (%s) nicht anwenden"
+msgstr "Konnte $sha1... ($rest) nicht anwenden"
 
 #: git-rebase--interactive.sh:549
 #, sh-format
 msgid ""
 "Could not amend commit after successfully picking $sha1... $rest\n"
 "This is most likely due to an empty commit message, or the pre-commit hook\n"
 "failed. If the pre-commit hook failed, you may need to resolve the issue "
 "before\n"
 "you are able to reword the commit."
 msgstr ""
+"Konnte Commit nicht nachbessern, nachdem dieser verwendet wurde: $sha1... $rest\n"
+"Das passierte sehr wahrscheinlich wegen einer leeren Commit-Beschreibung, oder\n"
+"weil der pre-commit Hook fehlschlug. Falls der pre-commit Hook fehlschlug,\n"
+"sollten Sie das Problem beheben, bevor Sie die Commit-Beschreibung ändern können."
 
 #: git-rebase--interactive.sh:564
 #, sh-format
 msgid "Stopped at $sha1_abbrev... $rest"
-msgstr ""
+msgstr "Angehalten bei $sha1_abbrev... $rest"
 
 #: git-rebase--interactive.sh:579
 #, sh-format
 msgid "Cannot '$squash_style' without a previous commit"
-msgstr ""
+msgstr "Kann nicht '$squash_style' ohne vorherigen Commit"
 
 #: git-rebase--interactive.sh:621
 #, sh-format
 msgid "Executing: $rest"
-msgstr ""
+msgstr "Führe aus: $rest"
 
 #: git-rebase--interactive.sh:629
 #, sh-format
 msgid "Execution failed: $rest"
-msgstr ""
+msgstr "Ausführung fehlgeschlagen: $rest"
 
 #: git-rebase--interactive.sh:631
-#, fuzzy
 msgid "and made changes to the index and/or the working tree"
-msgstr "weder den Index, noch das Arbeitsverzeichnis aktualisieren"
+msgstr "Der Index und/oder das Arbeitsverzeichnis wurde geändert."
 
 #: git-rebase--interactive.sh:633
-#, fuzzy
 msgid ""
 "You can fix the problem, and then run\n"
 "\n"
 "\tgit rebase --continue"
 msgstr ""
-"  (beheben Sie die Konflikte und führen Sie dann \"git rebase --continue\" "
-"aus)"
+"Sie können das Problem beheben, und dann\n"
+"\n"
+"\tgit rebase --continue\n"
+"\n"
+"ausführen."
 
 #. TRANSLATORS: after these lines is a command to be issued by the user
 #: git-rebase--interactive.sh:646
 #, sh-format
 msgid ""
 "Execution succeeded: $rest\n"
 "but left changes to the index and/or the working tree\n"
 "Commit or stash your changes, and then run\n"
 "\n"
 "\tgit rebase --continue"
 msgstr ""
+"Ausführung erfolgreich: $rest\n"
+"Aber Änderungen in Index oder Arbeitsverzeichnis verblieben.\n"
+"Committen Sie Ihre Änderungen oder benutzen Sie \"stash\".\n"
+"Führen Sie dann aus:\n"
+"\n"
+"\tgit rebase --continue"
 
 #: git-rebase--interactive.sh:657
-#, fuzzy, sh-format
+#, sh-format
 msgid "Unknown command: $command $sha1 $rest"
-msgstr "Unbekannter Unterbefehl: %s"
+msgstr "Unbekannter Befehl: $command $sha1 $rest"
 
 #: git-rebase--interactive.sh:658
 msgid "Please fix this using 'git rebase --edit-todo'."
-msgstr ""
+msgstr "Bitte beheben Sie das, indem Sie 'git rebase --edit-todo' ausführen."
 
 #: git-rebase--interactive.sh:693
 #, sh-format
 msgid "Successfully rebased and updated $head_name."
-msgstr ""
+msgstr "Erfolgreich Rebase ausgeführt und $head_name aktualisiert."
 
 #: git-rebase--interactive.sh:740
 msgid "Could not skip unnecessary pick commands"
-msgstr ""
+msgstr "Fehler beim Auslassen von nicht erforderlichen \"pick\"-Befehlen."
 
 #: git-rebase--interactive.sh:898
 #, sh-format
 msgid ""
 "Warning: the SHA-1 is missing or isn't a commit in the following line:\n"
 " - $line"
 msgstr ""
+"Warnung: Der SHA-1 in der folgenden Zeile fehlt oder ist kein Commit:\n"
+" - $line"
 
 #: git-rebase--interactive.sh:931
 #, sh-format
 msgid ""
 "Warning: the command isn't recognized in the following line:\n"
 " - $line"
 msgstr ""
+"Warnung: Das Kommando in der folgenden Zeile wurde nicht erkannt:\n"
+" - $line"
 
 #: git-rebase--interactive.sh:970
-#, fuzzy
 msgid "could not detach HEAD"
-msgstr "Konnte nicht von %s anfordern"
+msgstr "Konnte HEAD nicht loslösen"
 
 #: git-rebase--interactive.sh:1008
 msgid ""
 "Warning: some commits may have been dropped accidentally.\n"
 "Dropped commits (newer to older):"
 msgstr ""
+"Warnung: Einige Commits könnten aus Versehen entfernt worden sein.\n"
+"Entfernte Commits (neu zu alt):"
 
 #: git-rebase--interactive.sh:1016
 msgid ""
 "To avoid this message, use \"drop\" to explicitly remove a commit.\n"
 "\n"
 "Use 'git config rebase.missingCommitsCheck' to change the level of "
 "warnings.\n"
 "The possible behaviours are: ignore, warn, error."
 msgstr ""
+"Um diese Meldung zu vermeiden, benutzen Sie \"drop\", um exlizit Commits zu\n"
+"entfernen.\n"
+"\n"
+"Benutzen Sie 'git config rebase.missingCommitsCheck', um die Stufe der Warnungen\n"
+"zu ändern.\n"
+"Die möglichen Verhaltensweisen sind: ignore, warn, error."
 
 #: git-rebase--interactive.sh:1027
 #, sh-format
 msgid ""
 "Unrecognized setting $check_level for option rebase.missingCommitsCheck. "
 "Ignoring."
 msgstr ""
+"Nicht erkannte Einstellung $check_level für Option rebase.missingCommitsCheck.\n"
+"Ignoriere."
 
 #: git-rebase--interactive.sh:1044
 msgid "You can fix this with 'git rebase --edit-todo'."
-msgstr ""
+msgstr "Sie können das mit 'git rebase --edit-todo' beheben."
 
 #: git-rebase--interactive.sh:1045
 msgid "Or you can abort the rebase with 'git rebase --abort'."
-msgstr ""
+msgstr "Oder Sie können den Rebase mit 'git rebase --abort' abbrechen."
 
 #: git-rebase--interactive.sh:1069
-#, fuzzy
 msgid "Could not remove CHERRY_PICK_HEAD"
-msgstr "Konnte Commit von HEAD nicht auflösen\n"
+msgstr "Konnte CHERRY_PICK_HEAD nicht löschen"
 
 #: git-rebase--interactive.sh:1074
 #, sh-format
 msgid ""
 "You have staged changes in your working tree.\n"
 "If these changes are meant to be\n"
 "squashed into the previous commit, run:\n"
 "\n"
 "  git commit --amend $gpg_sign_opt_quoted\n"
 "\n"
 "If they are meant to go into a new commit, run:\n"
 "\n"
 "  git commit $gpg_sign_opt_quoted\n"
 "\n"
 "In both case, once you're done, continue with:\n"
 "\n"
 "  git rebase --continue\n"
 msgstr ""
+"Es befinden sich zum Commit vorgemerkte Änderungen in Ihrem Arbeitsverzeichnis.\n"
+"Wenn diese Änderungen in den vorherigen Commit aufgenommen werden sollen,\n"
+"führen Sie aus:\n"
+"\n"
+"  git commit --amend $gpg_sign_opt_quoted\n"
+"\n"
+"Wenn daraus ein neuer Commit erzeugt werden soll, führen Sie aus:\n"
+"\n"
+"  git commit $gpg_sign_opt_quoted\n"
+"\n"
+"Im Anschluss führen Sie zum Fortfahren aus:\n"
+"\n"
+"  git rebase --continue\n"
 
 #: git-rebase--interactive.sh:1091
 msgid "Error trying to find the author identity to amend commit"
 msgstr ""
+"Fehler beim Versuch die Identität des Authors zum Verbessern des Commits zu\n"
+"finden"
 
 #: git-rebase--interactive.sh:1096
 msgid ""
 "You have uncommitted changes in your working tree. Please commit them\n"
 "first and then run 'git rebase --continue' again."
 msgstr ""
+"Sie haben nicht committete Änderungen in Ihrem Arbeitsverzeichnis. Bitte\n"
+"committen Sie diese zuerst und führen Sie dann 'git rebase --continue' erneut\n"
+"aus."
 
 #: git-rebase--interactive.sh:1101 git-rebase--interactive.sh:1105
-#, fuzzy
 msgid "Could not commit staged changes."
-msgstr "Konnte Commit-Beschreibung nicht lesen: %s"
+msgstr "Konnte Änderungen aus der Staging-Area nicht committen."
 
 #: git-rebase--interactive.sh:1129
 msgid ""
 "\n"
 "You are editing the todo file of an ongoing interactive rebase.\n"
 "To continue rebase after editing, run:\n"
 "    git rebase --continue\n"
 "\n"
 msgstr ""
+"\n"
+"Sie bearbeiten gerade die TODO-Datei eines laufenden interaktiven Rebase.\n"
+"Um den Rebase nach dem Editieren fortzusetzen, führen Sie aus:\n"
+"    git rebase --continue\n"
+"\n"
 
 #: git-rebase--interactive.sh:1137 git-rebase--interactive.sh:1298
-#, fuzzy
 msgid "Could not execute editor"
-msgstr "Konnte %s nicht entfernen"
+msgstr "Konnte Editor nicht ausführen."
 
 #: git-rebase--interactive.sh:1145
 msgid "You need to set your committer info first"
 msgstr "Sie müssen zuerst die Informationen zum Commit-Ersteller setzen."
 
 #: git-rebase--interactive.sh:1153
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not checkout $switch_to"
-msgstr "Konnte Verzeichnis '%s' nicht erstellen."
+msgstr "Konnte $switch_to nicht auschecken."
 
 #: git-rebase--interactive.sh:1158
 msgid "No HEAD?"
-msgstr ""
+msgstr "Kein HEAD?"
 
 #: git-rebase--interactive.sh:1159
-#, fuzzy, sh-format
+#, sh-format
 msgid "Could not create temporary $state_dir"
-msgstr "konnte temporäre Datei '%s' nicht erstellen"
+msgstr "Konnte temporäres Verzeichnis $state_dir nicht erstellen."
 
 #: git-rebase--interactive.sh:1161
-#, fuzzy
 msgid "Could not mark as interactive"
-msgstr "Konnte Bereitstellung nicht lesen"
+msgstr "Konnte nicht als interaktiven Rebase markieren."
 
 #: git-rebase--interactive.sh:1171 git-rebase--interactive.sh:1176
-#, fuzzy
 msgid "Could not init rewritten commits"
-msgstr "Konnte Eltern-Commit %s nicht parsen\n"
+msgstr "Konnte neu geschriebene Commits nicht initialisieren."
 
 #: git-rebase--interactive.sh:1276
 #, sh-format
 msgid "Rebase $shortrevisions onto $shortonto ($todocount command)"
 msgid_plural "Rebase $shortrevisions onto $shortonto ($todocount commands)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Rebase von $shortrevisions auf $shortonto ($todocount Kommando)"
+msgstr[1] "Rebase von $shortrevisions auf $shortonto ($todocount Kommandos)"
 
 #: git-rebase--interactive.sh:1281
 msgid ""
 "\n"
 "However, if you remove everything, the rebase will be aborted.\n"
 "\n"
-msgstr ""
+msgstr "\nWenn Sie jedoch alles löschen, wird der Rebase abgebrochen.\n\n"
 
 #: git-rebase--interactive.sh:1288
 msgid "Note that empty commits are commented out"
-msgstr ""
+msgstr "Leere Commits sind auskommentiert."
 
 #: git-sh-setup.sh:89 git-sh-setup.sh:94
 #, sh-format
 msgid "usage: $dashless $USAGE"
-msgstr ""
+msgstr "Verwendung: $dashless $USAGE"
 
 #: git-sh-setup.sh:190
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot chdir to $cdup, the toplevel of the working tree"
 msgstr ""
-"Relative Pfade können nur von der obersten Ebene des Arbeitsverzeichnisses "
-"benutzt werden."
+"Konnte nicht in Verzeichnis $cdup wechseln, der obersten Ebene des\n"
+"Arbeitsverzeichnisses."
 
 #: git-sh-setup.sh:199 git-sh-setup.sh:206
 #, sh-format
 msgid "fatal: $program_name cannot be used without a working tree."
-msgstr ""
+msgstr "fatal: $program_name kann ohne ein Arbeitsverzeichnis nicht verwendet werden."
 
 #: git-sh-setup.sh:220
-#, fuzzy
 msgid "Cannot rebase: You have unstaged changes."
-msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Sie haben Änderungen, die "
-"nicht zum Commit vorgemerkt sind."
+msgstr "Rebase nicht möglich: Sie haben Änderungen, die nicht zum Commit vorgemerkt sind."
 
 #: git-sh-setup.sh:223
-#, fuzzy
 msgid "Cannot rewrite branches: You have unstaged changes."
 msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Sie haben Änderungen, die "
-"nicht zum Commit vorgemerkt sind."
+"Kann Branches nicht neu schreiben: Sie haben Änderungen, die nicht zum Commit\n"
+"vorgemerkt sind."
 
 #: git-sh-setup.sh:229
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot $action: You have unstaged changes."
 msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Sie haben Änderungen, die "
-"nicht zum Commit vorgemerkt sind."
+"Kann $action nicht ausführen: Sie haben Änderungen, die nicht zum Commit\n"
+"vorgemerkt sind."
 
 #: git-sh-setup.sh:242
-#, fuzzy
 msgid "Cannot rebase: Your index contains uncommitted changes."
-msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Die Staging-Area beinhaltet "
-"nicht committete Änderungen."
+msgstr "Rebase nicht möglich: Die Staging-Area beinhaltet nicht committete Änderungen."
 
 #: git-sh-setup.sh:248
-#, fuzzy, sh-format
+#, sh-format
 msgid "Cannot $action: Your index contains uncommitted changes."
 msgstr ""
-"Kann \"pull\" mit \"rebase\" nicht ausführen: Die Staging-Area beinhaltet "
-"nicht committete Änderungen."
+"Kann $action nicht ausführen: Die Staging-Area beinhaltet nicht committete\n"
+"Änderungen."
 
 #: git-sh-setup.sh:372
-#, fuzzy
 msgid "You need to run this command from the toplevel of the working tree."
-msgstr ""
-"Relative Pfade können nur von der obersten Ebene des Arbeitsverzeichnisses "
-"benutzt werden."
+msgstr "Sie müssen den Befehl von der obersten Ebene des Arbeitsverzeichnisses ausführen."
 
 #: git-sh-setup.sh:377
-#, fuzzy
 msgid "Unable to determine absolute path of git directory"
-msgstr "Konnte aktuelles Arbeitsverzeichnis nicht bekommen."
+msgstr "Konnte absoluten Pfad des Git-Verzeichnisses nicht bestimmen."
 
-- 
2.10.0.379.g97b919b


^ permalink raw reply related	[relevance 1%]

* Re: "Purposes, Concepts,Misfits, and a Redesign of Git" (a research paper)
  @ 2016-09-30 22:24  1% ` Jakub Narębski
       [not found]       ` <CAKbZu+BUOAjixTmEC4octseyJbMnFuaCTtLT9hx3H10=AECeKw@mail.gmail.com>
  0 siblings, 1 reply; 200+ results
From: Jakub Narębski @ 2016-09-30 22:24 UTC (permalink / raw)
  To: Konstantin Khomoutov, git
  Cc: Santiago Perez De Rosso, Daniel Jackson, Greg Wilson,
	Jakub Narębski

W dniu 30.09.2016 o 18:14, Konstantin Khomoutov pisze:

> The "It Will Never Work in Theory" blog has just posted a summary of a
> study which tried to identify shortcomings in the design of Git.
> 
> In the hope it might be interesting, I post this summary here.
> URL: http://neverworkintheory.org/2016/09/30/rethinking-git.html

I will comment on the article itself, not just on the summary.

| 2.2 Git
[...]
| But tracked files cannot be ignored; to ignore a tracked file
| one has to mark it as “assume unchanged.” This “assume
| unchanged” file will not be recognized by add; to make it
| tracked again this marking has to be removed.

WRONG!  Git has tracked files, untracked unignored files, and
untracked ignored files (mostly considered unimportant).

The "assume unchanged" bit is _performance_ optimization. It is not,
and cannot be a 'ignore tracked files' bit - here lies lost work!!!
You can use (imperfectly) "prefer worktree" bit hack instead.

You can say, if 'ignoring change to tracked files' is motivation,
or purpose, it lacks direct concept.

[...]
| As a result, when a user switches branches, files may be
| unexpectedly overwritten. 

This is possible _only_ if there are uncommitted changes. If they
are there, and they do not conflict with switching a branch, they
are "floated" to a newly checked out branch.

| Git fails with an error if there are any conflicting changes,
| effectively preventing the user from switching in this case.
| To mitigate this problem, Git provides a way to save versions
| of files to another storage area, called the “stash,” using
| a special command issued prior to the branch switch.

Or you can try to merge uncommitted changes with changes between
two branches: current and switched to.

Or you can forcibly discard your changes.

Or (with modern Git), you can put each branch in a separate
working area (with "git worktree"), though the article may predate
this feature.

[...]
| *Syncing with Other Repositories* Crucial to the understanding
| of how syncing with other repositories work is the notion
| of a “remote branch.” This is a branch (pointer to a commit)
| that (asynchronously) reflects the state of a branch in another
| repository. It is updated whenever there is some network
| communication (e.g., a push or fetch).

It is called "remote-tracking branch", rather than "remote branch".
At least in Git documentation. This branch is in local repository,
not in remote one. The remote-tracking branch for example
`origin/master` follows (tracks) branch `master` in remote
repository `origin`.

| The notion of a “remote branch” must not be confused
| with that of an “upstream branch.” An upstream branch is
| just a convenience for users: after the user assigns it to some
| branch, commands like pull and push default to use that
| branch for fetching and pushing changes if no branch is given
| as input.

Actually "upstream branch" (and related "upstream repository")
are a concept, not only a convenience. They denote a branch
(usually in remote repository) which is intended to ultimately
include changes in given branch. Note that "upstream branch"
can be set separately for any given local branch.

One thing that can enormously help recovering from errors, and
is not covered in the list of concepts is REFLOG.


[...]
| 3. Operational Misfits
[...]
| *Saving Changes* Suppose you are in the middle of a long
| task and want to save your changes, so that they can be later
| retrieved in case of failure. How would you do that?

You would use `git stash` or `git stash --include-untracked`!
In more complicated situations (during long-running operation
like resolving merge conflicts, interactive rebase, or finding
bugs with bisect) with modern Git you can create a new separate
working area with `git worktree`.

This also applies to the "*Switching branches*" problem (which
is more involved, as `git stash` would often not work, and if
it does it is harder to restore state - note however that stash
description includes the branch it was on).

So I would say that *Saving Changes* is solved with stash,
while *Switching Branches* remains a misfit.

| *Detached Head* Suppose you are working on some branch
| and realize that the last few commits you did are wrong, so
| you decide to go back to an old commit to start over again.
| You checkout that old commit and keep working creating
| commits. You might be surprised to discover that these new
| commits you’ve been working on belong to no branch at all.
| To avoid losing them you need to create a new branch or reset
| an existing one to point to the last commit.

It would be hard to be surprised unless one is in habit of
disregarding multi-line warning from Git... ;-)

I think it might be more of an UX problem, namely that the
`git checkout` command does too many things, which include
checking out revision (detaching HEAD, or landing on unnamed
branch, unless we create a new branch at the same time with
the '-b <newbranch>' option), and checking out a branch,
that is switching to other branch.

| *File Rename* Suppose you rename a file and make some
| changes to it. If you changed a significant portion of the file,
| then, as far as Git is concerned, you didn’t rename the file,
| but it is instead as if you deleted the old file and created a new
| one (which means that the file history is now lost). To work
| around this, you have to be diligent about creating a commit
| with the rename only, and only then creating a new commit
| with the modifications. This, however, likely creates a bogus
| commit that doesn’t correspond to a logical group of changes.

First, I think it might be inherent problem. The version control
system may implement *rename tracking* (store information about
renames), or *rename detection*. The latter is what Git does,
and it is what allows to do for example detecting copying and
movement of contents across files and within the same file
for `git blame` (and `git gui blame`) - which is impossible with
only rename tracking.

Nb. that handling file renames and other source reorganization
is important thing that modern version control systems should
be able to handle.

Second, the need for handling renames can be found in two
different operations. One is following history of a single
file across renames, or seeing a rename when looking at changes
in a single revision. The other is merging two lines of
development where one did a rename. The trick of splitting
large rename+change into pure rename and change without rename
can help only the former... the less important one. Merging
in Git is done using [recursive] 3-way merge strategy, which
takes into account only the endpoint state, and not history
between them - so if it was rename then change doesn't matter.

Third, (which is a bit of victim^W user blaming), large changes
are process smell. The cases when change accompanying rename
is so large that it screws heuristic based rename detection
legitimately are (or are supposed to be) rare. And for the
legitimate cases, that is end-of-line changes, there are
solutions to help (-w for diff, -Xrenormalize for merge).

| *File Tracking* Suppose you create a new file and then you
| add the file to start tracking changes to it. You keep working
| on the file making new modifications and then you make
| a vanilla commit. You might be surprised to find out that
| what actually got committed is the old version of the file
| (representing its state the last time the file was staged), and
| not the most recent one.

Unless one uses `git commit -a`, like most people (I think)
in most cases do.

Hopefully `git add -N`, aka. "intent to add", would help here...
when people switch to it to adding new files, and when the
feature gets improved (as it is now) to make it better and
easier to use (e.g. so "git diff" shows new i-t-a files).

| *Untracking File* Suppose there’s a database configuration
| file committed in the repository and you now want to edit
| this file to do some local testing. This new version of the
| file should not be committed. You could always leave out
| the file from the commit every time, but this is laborious and
| error-prone. You might think that you could make it ignored
| by modifying the `.gitignore` file but this doesn’t work for
| committed files.

The name "Untracking File" is misleading. You untrack file
(that is remove it from future commits) with `git rm --cached`.
No problem here. The name is "Ignore changes to tracked files",
or "Stopping tracking changes to file".

If you think of ignored files as unimportant, not precious,
then mismatch between understanding and what Git does would
lessen.

| The way to ignore this file is to mark it as
| “assume unchanged,” but this marking will be cleared when
| you switch to another branch.

s/“assume unchanged,”/“skip worktree,” (see earlier comment).

Right. Also, currently you need to use low-level commands
(`git update-index`) to mark file in this way.

[...]
| 4. Purposes for Version Control
[...]
| *Collaboration* To this point, all the purposes might apply in
| the context of a single user. Collaboration needs arise when
| multiple users work together on a single code base.
| /* ..........................................................
| /* _Purpose 4. Synchronize changes of collaborators_

One very important purpose that must be fulfilled before even
trying to synchronize changes is *isolation of changes*. Each
developer needs its own working area, so his or her changes do
not interfere with work of other developers.

Though "Disconnected operations" a bit overlaps (and is partial
superset) of this purpose.

See also intro to "Version Control by Example", by Eric Sink
http://ericsink.com/vcbe/html/intro.html

[...]
| 5.1 Stashing: An Example
|
| We consider the motivating purpose of stashing not to be
| a subpurpose of any of the high-level purposes for version
| control (§4). This section elaborates on our rationale for this.
|
| Take (what seem to be) the motivating use cases for stashing
| [9, Chapter 7.3]: (1) to pull into a dirty working directory
| and (2) to deal with an interruption in your workflow

Actually (1) is not a separate use case, but a subset 
(specialization) of (2) - and interruption in your workflow,
where the interruption is pull.

Note that to synchronize with remote repository one should use
fetch, not pull.  The latter is more involved operation, and
should be considered interruption.  Also, rarer if using
feature branches workflow, and not working on long-lived
stabilization branches directly.

[...]
| The problem
| is the lack of connection between this purpose and the highlevel
| purposes for version control, which suggests that the
| introduction of stashing might be to patch flaws in the design
| of Git and not to satisfy a requirement of version control.

Or the problem might be that you are missing some (maybe minor)
requirement of version control system. Just saying...

| 6. Analysis
[...]
| *Divided Ignored and Assumed Unchanged*

This ignores the fact that (unstated) assumption is that ignored
files are considered not important (or at least less important;
Git cares less about changes in those files, and may in some
cases make you loose changes to them).

Ignore file != ignore changes, though it may look like it is.

[...]
| 7. Gitless
|
| 7.1 Overview
|
| Gitless has no staging area, and the only file classifications
| are “tracked,” “untracked,” “ignored,” and “in conflict.”

Without staging area, I wonder how you would be able to handle
well different types of integration conflicts, which are not
limited to CONFLICT(content).

You also loose the ability to select subset of *changes* to
be committed, not only files.  This is often very useful, see
http://tomayko.com/writings/the-thing-about-git
http://2ndscale.com/rtomayko/2008/the-thing-about-git

[...]
| A branch in Gitless is a completely independent line of
| development: each branch includes the working version of
| files [...]

If I understand your model correctly, you would get rid of
one problem / mismatch, but get into other. What would you
do if you started work on some branch, and then realized
that you should have been working on a new topic branch?
Or you realized that you are on wrong branch, and want to
move changes?

Ah, I haven't realized that it is described later (well,
at least the first case):

: In regard to branching, to address situations in which the
: user wants changes made in the current branch to be moved
: onto the destination branch (e.g., the user realizes that she
: has been working in the wrong branch), the Gitless branch
: command has a `move-over` flag


[...]
|  Also, there
| is no possible way of getting in a “detached head” state; at
| any time, the user is always working on some branch (the
| “current” branch). Head is a per-branch reference to the last
| commit of the branch.

How do you solve the problem of checking out the state of
the tag, that is the state of repository at given revision?

Also during some long lived multi-step operations, like bisect
or interactive rebase, you are not really on any branch,

| 7.2.1 Discussion
[...]
| There could be other use cases for the
| staging area that Gitless doesn’t handle well but we expect
| these to be fairly infrequent.

Like handling merge conflict...??? Infrequent doesn't mean
unimportant.


That's all my comments for now.


This is a very interesting research.  Those problems (misfits)
are legitimate concern.  Even if it would not result in changes
to how Git works, it should improve how we are talking about
version control, and how we design them (that includes GUIs
that work above version control systems).

Best regards,
-- 
Jakub Narębski


^ permalink raw reply	[relevance 1%]

* Re: [PATCH] diff-highlight: add some tests.
  2016-08-19 20:44  4%   ` Junio C Hamano
@ 2016-08-19 21:04  0%     ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2016-08-19 21:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Brian Henderson, git, e

On Fri, Aug 19, 2016 at 01:44:28PM -0700, Junio C Hamano wrote:

> Brian Henderson <henderson.bj@gmail.com> writes:
> 
> > Junio, how does this look?
> > ...
> > +# dh_test is a test helper function which takes 1) some file data, 2) some
> > +# change of the file data, creates a diff and commit of the changes and passes
> > +# that through diff-highlight.
> > +# The optional 3rd parameter is the expected output of diff-highlight minus the
> > +# diff/commit header. This parameter is given directly to printf as the format
> > +# string (in order to properly handle ascii escape codes; CW, CR), so any '%'
> > +# need to be doubled to protect it.
> > +# Don't include a 3rd parameter if diff-highlight is supposed to leave the
> > +# input unmodified.
> > +# For convienence, the 3rd parameter can begin with a newline which will be
> > +# stripped.
> 
> You seem to be stripping any and all empty lines with "perl -pe"; I
> am not sure if that is sensible.
> 
> I really do not see the point of being able to spell
> 
> "
> aaa
> bbb
> "
> 
> when you can perfectly well read
> 
> "aaa
> bbb"
> 
> or even "aaa\nbbb\n" for that matter.  I personally do not think the
> difference is worth the cost of an extra invocation of Perl, but we
> already saw how stubborn you are, so there is no point spending my
> time on trying to convince you further.  Assuming that it is so
> precious that the input can start with an extra blank line, what you
> wrote is a sensible implementation.

I didn't want to bikeshed, so I resisted saying so up until now, but I
actually think:

  dh_test \
    "aaa\nbbb\nccc\n" \
    "aaa\n0bb\nccc\n" \
    <<-EOF
  aaa
  -${CW}b${CR}bb
  +${CW}0${CR}bb
  EOF

might before readable, if only because it lets you indent the content to
match the rest of the test content. For that matter, I'm not sure that:

  cat >a <<-\EOF &&
  aaa
  bbb
  ccc
  EOF

  cat >b <<-\EOF &&
  aaa
  0bb
  ccc
  EOF

  dh_test a b <<\EOF
  aaa
  -${CW}b${CR}bb
  +${CW}0${CR}bb
  EOF

isn't more readable, too. It's more lines, certainly, but it makes it
very easy to see what the input files look like, rather than cramming
"\n" into the middle of a string (the existing code does make the diff
easy to see for _this_ case, because the pre- and post-image line up
vertically, but that is only the case for pure transliterations like
this).

Just my two cents.

-Peff

^ permalink raw reply	[relevance 0%]

* Re: [PATCH] diff-highlight: add some tests.
  @ 2016-08-19 20:44  4%   ` Junio C Hamano
  2016-08-19 21:04  0%     ` Jeff King
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2016-08-19 20:44 UTC (permalink / raw)
  To: Brian Henderson; +Cc: git, peff, e

Brian Henderson <henderson.bj@gmail.com> writes:

> Junio, how does this look?
> ...
> +# dh_test is a test helper function which takes 1) some file data, 2) some
> +# change of the file data, creates a diff and commit of the changes and passes
> +# that through diff-highlight.
> +# The optional 3rd parameter is the expected output of diff-highlight minus the
> +# diff/commit header. This parameter is given directly to printf as the format
> +# string (in order to properly handle ascii escape codes; CW, CR), so any '%'
> +# need to be doubled to protect it.
> +# Don't include a 3rd parameter if diff-highlight is supposed to leave the
> +# input unmodified.
> +# For convienence, the 3rd parameter can begin with a newline which will be
> +# stripped.

You seem to be stripping any and all empty lines with "perl -pe"; I
am not sure if that is sensible.

I really do not see the point of being able to spell

"
aaa
bbb
"

when you can perfectly well read

"aaa
bbb"

or even "aaa\nbbb\n" for that matter.  I personally do not think the
difference is worth the cost of an extra invocation of Perl, but we
already saw how stubborn you are, so there is no point spending my
time on trying to convince you further.  Assuming that it is so
precious that the input can start with an extra blank line, what you
wrote is a sensible implementation.

> +dh_test () {
> +	a="$1" b="$2" &&
> +
> +	{
> +		printf "$a" >file &&
> +		git add file &&
> +		git commit -m "Add a file" &&
> +
> +		printf "$b" >file &&
> +		git diff file >diff.raw &&
> +		git commit -am "Update a file" &&
> +		git show >commit.raw
> +	} >/dev/null &&
> +
> +	if test $# -ge 3

I think

	if test $# = 3

is much better; you would want to catch bugs in a caller that gave
you fourth parameter by mistake, instead of silently ignoring it.

> +test_strip_patch_header () {
> +	sed -e '1,/^@@/d' "$@"
> +}

While I think it is a great idea to hide the sed command behind a
helper function for readability, I am not sure "strip patch header"
is a great name that describes what it does.  A natural expectation
for an operation with that name done to this input:

    diff --git a/file b/file
    index fffffff..fffffff 100644
    --- a/file
    +++ b/file
    @@ -l,k +m,n @@ comments
     common
    -old
    +new
     common
    @@ -l,k +m,n @@ more comments
     common
    +added more
    +added even more

would be to remove the first four lines, not five.


^ permalink raw reply	[relevance 4%]

* [PATCH 1/1] do not add common-main to lib
@ 2016-08-15  7:52  4% Christian Hesse
  0 siblings, 0 replies; 200+ results
From: Christian Hesse @ 2016-08-15  7:52 UTC (permalink / raw)
  To: git; +Cc: Christian Hesse

From: Christian Hesse <mail@eworm.de>

Commit 08aade70 (mingw: declare main()'s argv as const) changed
declaration of main function. This breaks linking external projects
(e.g. cgit) to libgit.a with:

error: Multiple definition of `main'

So do not add common-main to lib and let projects have their own
main function.

Signed-off-by: Christian Hesse <mail@eworm.de>
---
 Makefile | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/Makefile b/Makefile
index d96ecb7..1aea768 100644
--- a/Makefile
+++ b/Makefile
@@ -953,7 +953,8 @@ BUILTIN_OBJS += builtin/verify-tag.o
 BUILTIN_OBJS += builtin/worktree.o
 BUILTIN_OBJS += builtin/write-tree.o
 
-GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB)
+GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
+GITCOMMON = common-main.o $(GITLIBS)
 EXTLIBS =
 
 GIT_USER_AGENT = git/$(GIT_VERSION)
@@ -1593,15 +1594,15 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
 DIFF_SQ = $(subst ','\'',$(DIFF))
 PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
 
-# We must filter out any object files from $(GITLIBS),
+# We must filter out any object files from $(GITCOMMON),
 # as it is typically used like:
 #
-#   foo: foo.o $(GITLIBS)
+#   foo: foo.o $(GITCOMMON)
 #	$(CC) $(filter %.o,$^) $(LIBS)
 #
 # where we use it as a dependency. Since we also pull object files
 # from the dependency list, that would make each entry appear twice.
-LIBS = $(filter-out %.o, $(GITLIBS)) $(EXTLIBS)
+LIBS = $(filter-out %.o, $(GITCOMMON)) $(EXTLIBS)
 
 BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
 	$(COMPAT_CFLAGS)
@@ -1741,7 +1742,7 @@ git.sp git.s git.o: EXTRA_CPPFLAGS = \
 	'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
 	'-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
 
-git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
+git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
 		$(filter %.o,$^) $(LIBS)
 
@@ -2033,21 +2034,21 @@ compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
 compat/nedmalloc/nedmalloc.sp: SPARSE_FLAGS += -Wno-non-pointer-null
 endif
 
-git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
+git-%$X: %.o GIT-LDFLAGS $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
-git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(LIBS) $(IMAP_SEND_LDFLAGS)
 
-git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
+git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(LIBS)
-git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
+git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
-git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
+git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITCOMMON) $(VCSSVN_LIB)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
 	$(VCSSVN_LIB)
 
@@ -2057,7 +2058,7 @@ $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
 	ln -s $< $@ 2>/dev/null || \
 	cp $< $@
 
-$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS)
+$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
 
@@ -2271,7 +2272,7 @@ t/helper/test-svn-fe$X: $(VCSSVN_LIB)
 
 .PRECIOUS: $(TEST_OBJS)
 
-t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
+t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITCOMMON)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
 check-sha1:: t/helper/test-sha1$X
-- 
2.9.3


^ permalink raw reply related	[relevance 4%]

* Re: patch submission process, was Re: [PATCH v6 06/16] merge_recursive: abort properly upon errors
  @ 2016-08-04 15:58  3%                   ` Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2016-08-04 15:58 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Junio C Hamano, Git Mailing List, Eric Sunshine, Jeff King,
	Johannes Sixt, Duy Nguyen, Jakub Narębski

Hi Stefan,

On Wed, 3 Aug 2016, Stefan Beller wrote:

> On Wed, Aug 3, 2016 at 9:07 AM, Johannes Schindelin
> <Johannes.Schindelin@gmx.de> wrote:
> >
> > On Wed, 3 Aug 2016, Junio C Hamano wrote:
> >
> >> On Wed, Aug 3, 2016 at 4:59 AM, Johannes Schindelin
> >> <Johannes.Schindelin@gmx.de> wrote:
> >> >
> >> > I disagree, however, with the suggestion to sift through your `pu`
> >> > branch and to somehow replace local branches with the commits found
> >> > there.
> >>
> >> To be more in line with the "e-mailed patch" workflow, I think what I
> >> should do is to send the version I queued with fixups back to the
> >> list as follow-up.  Just like reviewers review, the maintainer
> >> reviews and queues, the original author should be able to work in the
> >> same workflow, i.e. reading and applying an improved version of the
> >> patch from her mailbox.
> >
> > You seem to assume that it isn't cumbersome for people like me to
> > extract patches out of mails and to replace existing commits using
> > those patches.
> >
> > So it probably comes as a huge surprise to you to learn that this *is*
> > cumbersome for me.
> 
> It is also cumbersome for me, because I never had the need to setup a
> proper mail client that has the strength to apply patches. The need was
> not there as I tend to apply only rarely patches by email, so I can go
> the painful way each time.

The reason is clear, too. Mail clients serve humans. That is their
purpose. Humans do not care all that much whether the text was preserved
exactly as the sender wrote it, except rich text (read: HTML), of course.

> > I got too used to the ease of git push, git pull with or without
> > --rebase, and many other Git commands. Having to transmogrify code
> > changes from commits in Git into a completely different universe:
> > plain text patches in my mailbox, and back, losing all kinds of data
> > in the process, is just not at all that easy. And it costs a lot of
> > time.
> >
> > In short: if you start "submitting patches" back to me via mail, it
> > does not help me. It makes things harder for me. In particular when
> > you add your sign-off to every patch and I have to strip it.
> 
> You don't have to strip the sign off, as it shows the flow of the patch,
> e.g.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> 
> may indicate you proposed a patch, Junio picked it up (and fixed a typo
> optionally), I obtained the patch (via mail, via Git?) improved it, you
> improved it further and then Junio took it and merged it upstream.

Recently, I got yelled at because I took one of Junio's patches, made a
couple of changes, and *added* my sign-off.

Before that incident, I agreed with you that it may make for a nice record
of the back-and-forth that eventually resulted in the patch in question.
Now, I am not so sure anymore.

> > If you change your workflow, I would humbly request that you do it in
> > a way that makes things easier on both sides, not harder.
> 
> When attending the Git Merge conference in May, gregkh said roughtly:
> "We deliberately waste developers time, because it is not scarce.
> Maintainers time is scarce however " and it stuck with me. (and I am a
> developer, not a maintainer ;( so at least the kernel community deems it
> ok to waste my time).

Yeah. It was not the only thing I disagreed with in his talk. To be a
little bit blunt (by my standards, not by LKML's standards, that is): the
Linux kernel mailing list is not necessarily anything I would want to use
as a role model.

I agree that maintainers' time is scarce.

I am one.

So of course I agree with that statement. What I disagree with is that it
is okay to *waste* contributors' time. That's just inconsiderate. And I
say that also because I am a contributor *in addition* to being a
maintainer.

As a consequence, I commend Greg for recognizing that the patch submission
process must be light on the maintainer. And I would have commended him
even further if he had realized that proper tooling should waste nothing,
and no one's time.

> While that is true for the kernel community, I guess it is also true for
> the Git community, unless Junio (and the community) want to appoint a
> bunch of maintainer lieutenants, such that they outnumber the number of
> developers, e.g. divided by areas of the code: a refs backend
> maintainer, a submodule maintainer, ...  or rather by area of usage: a
> porcelain UI maintainer, a git-on-server maintainer.

As I mentioned earlier, I do not care much about following LKML's example.

What I see on this here list is that many a potential contributor is
scared away, that we waste precious time (also the maintainer's) pointing
out in what way certain contributions do not follow the guide lines, and
that even old-timers sometimes submit patches that are white-space
corrupted.

That is a *huge* waste of time. In my opinion, the culprit is that we do
not use appropriate tools. To a mail client, everything looks like a nail.
Wrong metaphor, but you get the point.

> > It would be a totally different matter, of course, if you used the
> > branches I publish via my GitHub repository, added fixup! and squash!
> > commits, published the result to a public repository and then told me
> > to pull from there, that would make things easier. We could even
> > introduce a reword! construct, to make the review of the suggested
> > edits of the commit message easier. I could easily verify that my
> > branch head agrees with the base commit of your branch, I could build
> > proper tooling around this workflow, and it would lighten my load.
> >
> > I guess what I am saying is that we might just as well start using this
> > awesome tool to work with code, that tool named "Git".
> 
> I think Git itself is for the tracking the code and managing it, e.g.
> merging, moving, keeping it. That doesn't quite include modifying and
> creating code (e.g. there is no "git edit" command)

Git is not only for tracking the code. It knows about editors
(core.editor), it can export .zip files (git-archive), it can show
human-readable (not machine-readable) word diffs, etc.

Whenever we needed a certain functionality, we added it.

> If we were to change our workflows drastically, I'd propose to
> go a way[1] similar to notedb in Gerrit, or git-series,

Gerrit is a huge, non-distributed system. Complex, too. If we change the
patch submission process, we should make things *easier*, not *harder*. So
I think Gerrit is pretty much out of the question.

Even requiring every contributor to register with GitHub would be too much
of a limitation, I would wager.

And when I said I have zero interest in tools that use the "latest and
greatest language", I was hinting at git-series. Rust may be a fine and
wonderful language. Implementing git-series in Rust, however, immediately
limited the potential engagement with developers dramatically.

Additionally, I would like to point out that defining a way to store
reviews in Git is not necessarily improving the way our code contribution
process works. If you want to record the discussions revolving around the
code, I think public-inbox already does a pretty good job at that.

I guess I have no really good idea yet, either, how to retain the ease of
access of sending mails to the list, yet somehow keep a strong tie with
the original data stored in Git.

Ciao,
Dscho

^ permalink raw reply	[relevance 3%]

* Re: [RFC/PATCH v11 13/13] bisect--helper: `bisect_start` shell function partially in C
  2016-08-02 20:19  5%   ` Junio C Hamano
@ 2016-08-03 20:49  4%     ` Pranit Bauva
  0 siblings, 0 replies; 200+ results
From: Pranit Bauva @ 2016-08-03 20:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git List

Hey Junio,

On Wed, Aug 3, 2016 at 1:49 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Pranit Bauva <pranit.bauva@gmail.com> writes:
>
>> +static int bisect_start(struct bisect_terms *terms, int no_checkout,
>> +                     const char **argv, int argc)
>> +{
>> +     int i, j, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
>> +     int flag;
>> +     struct string_list revs = STRING_LIST_INIT_DUP;
>> +     struct string_list states = STRING_LIST_INIT_DUP;
>> +     struct strbuf start_head = STRBUF_INIT;
>> +     const char *head;
>> +     unsigned char sha1[20];
>> +     FILE *fp;
>> +     struct object_id oid;
>> +
>> +     if (is_bare_repository())
>> +             no_checkout = 1;
>> +
>> +     for(i = 0; i < argc; i++) {
>
> SP after for.

Sure!

>> +             if (!strcmp(argv[i], "--")) {
>> +                     has_double_dash = 1;
>> +                     break;
>> +             }
>> +             if (!strcmp(argv[i], "--term-good")) {
>> +                     must_write_terms = 1;
>> +                     strbuf_reset(&terms->term_good);
>> +                     strbuf_addstr(&terms->term_good, argv[++i]);
>> +                     break;
>> +             }
>> +             if (!strcmp(argv[i], "--term-bad")) {
>> +                     must_write_terms = 1;
>> +                     strbuf_reset(&terms->term_bad);
>> +                     strbuf_addstr(&terms->term_bad, argv[++i]);
>> +                     break;
>> +             }
>
> The original was not careful, either, but what if the user ends the
> command line with "--term-good", without anything after it?

> Also the original is prepared to handle --term-good=boa; because
> this function can be be called directly from the UI (i.e. "git
> bisect start --term-good=boa"), not supporting that form would be
> seen as a regression.


I wanted to discuss this precisely by this RFC. I was initially
thinking of using OPT_ARGUMENT() for bisect_terms() which would in
turn cover up for bisect_start() too. Currently the code does not
support --term-good=boa because it treats --term-good as a boolean Do
you have any other thing in mind?

>> +             if (starts_with(argv[i], "--") &&
>> +                 !one_of(argv[i], "--term-good", "--term-bad", NULL)) {
>> +                     string_list_clear(&revs, 0);
>> +                     string_list_clear(&states, 0);
>> +                     die(_("unrecognised option: '%s'"), argv[i]);
>> +             }
>> +             if (get_oid(argv[i], &oid) || has_double_dash) {
>
> Calling get_oid() alone is insufficient to make sure argv[i] refers
> to an existing object that is a committish.  The "^{commit}" suffix
> in the original is there for a reason.

Yes sure!

>> +                     string_list_clear(&revs, 0);
>> +                     string_list_clear(&revs, 0);
>
> You seem to want the revs list really really clean ;-)

Haha! ;) My bad. Will remove the extra line!

>> +                     die(_("'%s' does not appear to be a valid revision"), argv[i]);
>> +             }
>> +             else
>> +                     string_list_append(&revs, oid_to_hex(&oid));
>> +     }
>> +
>> +     for (j = 0; j < revs.nr; j++) {
>
> Why "j", not "i", as clearly the previous loop has finished at this
> point?  The only reason why replacing "j" with "i" would make this
> function buggy would be if a later part of this function depended on
> the value of "i" when the control left the above loop, but if that
> were the case (I didn't check carefully), such a precious value that
> has long term effect throughout the remainder of the function must
> not be kept in an otherwise throw-away loop counter variable "i".
>
> Introduce a new "int pathspec_pos" and set it to "i" immediately
> after the "for (i = 0; i < argc; i++) { ... }" loop above, perhaps.

I am using i afterwards for writing the arguments to BISECT_NAMES. But
I think it would be better to use pathspec_pos and discard j
altogether. Thanks!
>
>> +             struct strbuf state = STRBUF_INIT;
>> +             /*
>> +              * The user ran "git bisect start <sha1> <sha1>", hence
>> +              * did not explicitly specify the terms, but we are already
>> +              * starting to set references named with the default terms,
>> +              * and won't be able to change afterwards.
>> +              */
>> +             must_write_terms = 1;
>> +
>> +             if (bad_seen)
>> +                     strbuf_addstr(&state, terms->term_good.buf);
>> +             else {
>> +                     bad_seen = 1;
>> +                     strbuf_addstr(&state, terms->term_bad.buf);
>> +             }
>> +             string_list_append(&states, state.buf);
>> +             strbuf_release(&state);
>> +     }
>
> How about this instead?
>
>         /*
>          * that comment block goes here
>          */
>         must_write_terms = !!revs.nr;
>         for (i = 0; i < revs.nr; i++) {
>                 if (bad_seen)
>                         string_list_append(&states, terms->term_good.buf);
>                 else
>                         string_list_append(&states, terms->term_bad.buf);
>         }

Seems better. Thanks!

>> +
>> +     /*
>> +      * Verify HEAD
>> +      */
>> +     head = resolve_ref_unsafe("HEAD", 0, sha1, &flag);
>
> The last parameter is a set of flag bits, so call it flags.

Sure!

>> +     if (!head) {
>> +             if (get_sha1("HEAD", sha1)) {
>> +                     string_list_clear(&revs, 0);
>> +                     string_list_clear(&states, 0);
>> +                     die(_("Bad HEAD - I need a HEAD"));
>
> We see many repeated calls to clear these two string lists before
> exiting with failure, either by dying or return -1.
>
> I wonder how bad the resulting code would look like if we employed
> the standard pattern of having a "fail_return:" label at the end of
> the function (after the "return" for the usual control flow) to
> clear them.  If the result becomes less readable (and I suspect that
> you would end up making it less readable), leaving the current code
> structure is OK.

Its becoming really bad. I tried it once. Different things are being
cleaned up at different times which makes it all the more tedious to
maintain.

>> +             }
>> +     }
>> +     if (!is_empty_or_missing_file(git_path_bisect_start())) {
>> +             /* Reset to the rev from where we started */
>> +             strbuf_read_file(&start_head, git_path_bisect_start(), 0);
>> +             strbuf_trim(&start_head);
>> +             if (!no_checkout) {
>> +                     struct argv_array argv = ARGV_ARRAY_INIT;
>> +                     argv_array_pushl(&argv, "checkout", start_head.buf,
>> +                                      "--", NULL);
>> +                     if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
>> +                             error(_("checking out '%s' failed. Try again."),
>> +                                   start_head.buf);
>
> The original suggests to try "git bisect reset" here to recover.

Will include it.

>> +                             strbuf_release(&start_head);
>> +                             string_list_clear(&revs, 0);
>> +                             string_list_clear(&states, 0);
>> +                             return -1;
>> +                     }
>> +             }
>> +     } else {
>> +             if (starts_with(head, "refs/head/") || !get_oid(head, &oid)) {
>
> get_oid() is insufficient to ensure what you have in $head is
> 40-hex.  I think you meant get_oid_hex() here.

Yes definitely. Might have been missed.

>> +                     /*
>> +                      * This error message should only be triggered by
>> +                      * cogito usage, and cogito users should understand
>> +                      * it relates to cg-seek.
>> +                      */
>> +                     if (!is_empty_or_missing_file(git_path_head_name())) {
>> +                             strbuf_release(&start_head);
>> +                             string_list_clear(&revs, 0);
>> +                             string_list_clear(&states, 0);
>> +                             die(_("won't bisect on cg-seek'ed tree"));
>> +                     }
>> +                     if (starts_with(head, "refs/heads/")) {
>
> skip_prefix(), perhaps, if "head" is no longer used from here on?

Sure!

>> +     /*
>> +      * Write new start state
>> +      */
>> +     fp = fopen(git_path_bisect_start(), "w");
>> +     if (!fp) {
>> +             bisect_clean_state();
>> +             strbuf_release(&start_head);
>> +             string_list_clear(&revs, 0);
>> +             string_list_clear(&states, 0);
>> +             return -1;
>> +     }
>> +     if (!fprintf(fp, "%s\n", start_head.buf)) {
>
> man 3 fprintf and look for "Return Value"?

I should have been more careful about fprintf's return value.

>> +             fclose(fp);
>> +             bisect_clean_state();
>> +             strbuf_release(&start_head);
>> +             string_list_clear(&revs, 0);
>> +             string_list_clear(&states, 0);
>> +             return -1;
>> +     }
>> +     fclose(fp);
>
> Perhaps use write_file() instead of the above block of text?

Yes, that seems better. Thanks!

>> +     if (no_checkout) {
>> +             get_oid(start_head.buf, &oid);
>> +             if (update_ref(NULL, "BISECT_HEAD", oid.hash, NULL, 0,
>> +                            UPDATE_REFS_MSG_ON_ERR)) {
>
> Doesn't the original use --no-deref for this update-ref call?

Yes, will change.

>> +                     bisect_clean_state();
>> +                     strbuf_release(&start_head);
>> +                     string_list_clear(&revs, 0);
>> +                     string_list_clear(&states, 0);
>> +                     return -1;
>> +             }
>> +     }
>> +     strbuf_release(&start_head);
>> +     fp = fopen(git_path_bisect_names(), "w");
>> +
>> +     for (; i < argc; i++) {
>> +             if (!fprintf(fp, "%s ", argv[i])) {
>
> man 3 fprintf and look for "Return Value"?
>
> More importantly, the original does --sq-quote so that BISECT_NAMES
> file can be read back by a shell.  This is important as argv[i] can
> have whitespace in it, and you are concatenating them with SP in
> between here.  Also you are not terminating that line.

Yes its a good idea to retain its --sq-quote nature.

>> +                     fclose(fp);
>> +                     bisect_clean_state();
>> +                     string_list_clear(&revs, 0);
>> +                     string_list_clear(&states, 0);
>> +                     return -1;
>> +             }
>> +     }
>> +     fclose(fp);
>
> Perhaps
>
>         strbuf_reset(&bisect_names);
>         if (pathspec_pos < argc)
>                 sq_quote_argv(&bisect_names, argv + pathspec_pos, 0);
>         write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
>
> or something like that?

Yes! Thanks! Looks pretty good to me.

>> +     for (j = 0; j < states.nr; j ++) {
>
> Again, is "i" still precious here?  Style: drop SP between j and ++.

After BISECT_NAMES, "i" ceases to be precious.

>> +     fp = fopen(git_path_bisect_log(), "a");
>> +     if (!fp) {
>> +             bisect_clean_state();
>> +             return -1;
>> +     }
>> +     if (!fprintf(fp, "git bisect start")) {
>> +             bisect_clean_state();
>> +             return -1;
>> +     }
>> +     for (i = 0; i < argc; i++) {
>> +             if (!fprintf(fp, " '%s'", argv[i])) {
>> +                     fclose(fp);
>> +                     bisect_clean_state();
>> +                     return -1;
>> +             }
>> +     }
>> +     if (!fprintf(fp, "\n")) {
>> +             fclose(fp);
>> +             bisect_clean_state();
>> +             return -1;
>> +     }
>
> Again, the original writes orig_args which was protected with --sq-quote.

Yes. Will take care of it.

>> +     fclose(fp);
>> +
>> +     return 0;
>> +}
>> +

Regards,
Pranit Bauva

^ permalink raw reply	[relevance 4%]

* Re: [RFC/PATCH v11 13/13] bisect--helper: `bisect_start` shell function partially in C
  @ 2016-08-02 20:19  5%   ` Junio C Hamano
  2016-08-03 20:49  4%     ` Pranit Bauva
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2016-08-02 20:19 UTC (permalink / raw)
  To: Pranit Bauva; +Cc: git

Pranit Bauva <pranit.bauva@gmail.com> writes:

> +static int bisect_start(struct bisect_terms *terms, int no_checkout,
> +			const char **argv, int argc)
> +{
> +	int i, j, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
> +	int flag;
> +	struct string_list revs = STRING_LIST_INIT_DUP;
> +	struct string_list states = STRING_LIST_INIT_DUP;
> +	struct strbuf start_head = STRBUF_INIT;
> +	const char *head;
> +	unsigned char sha1[20];
> +	FILE *fp;
> +	struct object_id oid;
> +
> +	if (is_bare_repository())
> +		no_checkout = 1;
> +
> +	for(i = 0; i < argc; i++) {

SP after for.

> +		if (!strcmp(argv[i], "--")) {
> +			has_double_dash = 1;
> +			break;
> +		}
> +		if (!strcmp(argv[i], "--term-good")) {
> +			must_write_terms = 1;
> +			strbuf_reset(&terms->term_good);
> +			strbuf_addstr(&terms->term_good, argv[++i]);
> +			break;
> +		}
> +		if (!strcmp(argv[i], "--term-bad")) {
> +			must_write_terms = 1;
> +			strbuf_reset(&terms->term_bad);
> +			strbuf_addstr(&terms->term_bad, argv[++i]);
> +			break;
> +		}

The original was not careful, either, but what if the user ends the
command line with "--term-good", without anything after it?

Also the original is prepared to handle --term-good=boa; because
this function can be be called directly from the UI (i.e. "git
bisect start --term-good=boa"), not supporting that form would be
seen as a regression.

> +		if (starts_with(argv[i], "--") &&
> +		    !one_of(argv[i], "--term-good", "--term-bad", NULL)) {
> +			string_list_clear(&revs, 0);
> +			string_list_clear(&states, 0);
> +			die(_("unrecognised option: '%s'"), argv[i]);
> +		}
> +		if (get_oid(argv[i], &oid) || has_double_dash) {

Calling get_oid() alone is insufficient to make sure argv[i] refers
to an existing object that is a committish.  The "^{commit}" suffix
in the original is there for a reason.

> +			string_list_clear(&revs, 0);
> +			string_list_clear(&revs, 0);

You seem to want the revs list really really clean ;-)

> +			die(_("'%s' does not appear to be a valid revision"), argv[i]);
> +		}
> +		else
> +			string_list_append(&revs, oid_to_hex(&oid));
> +	}
> +
> +	for (j = 0; j < revs.nr; j++) {

Why "j", not "i", as clearly the previous loop has finished at this
point?  The only reason why replacing "j" with "i" would make this
function buggy would be if a later part of this function depended on
the value of "i" when the control left the above loop, but if that
were the case (I didn't check carefully), such a precious value that
has long term effect throughout the remainder of the function must
not be kept in an otherwise throw-away loop counter variable "i".

Introduce a new "int pathspec_pos" and set it to "i" immediately
after the "for (i = 0; i < argc; i++) { ... }" loop above, perhaps.

> +		struct strbuf state = STRBUF_INIT;
> +		/*
> +		 * The user ran "git bisect start <sha1> <sha1>", hence
> +		 * did not explicitly specify the terms, but we are already
> +		 * starting to set references named with the default terms,
> +		 * and won't be able to change afterwards.
> +		 */
> +		must_write_terms = 1;
> +
> +		if (bad_seen)
> +			strbuf_addstr(&state, terms->term_good.buf);
> +		else {
> +			bad_seen = 1;
> +			strbuf_addstr(&state, terms->term_bad.buf);
> +		}
> +		string_list_append(&states, state.buf);
> +		strbuf_release(&state);
> +	}

How about this instead?

	/*
         * that comment block goes here
         */
       	must_write_terms = !!revs.nr;
	for (i = 0; i < revs.nr; i++) {
                if (bad_seen)
                	string_list_append(&states, terms->term_good.buf);
		else
                	string_list_append(&states, terms->term_bad.buf);
	}

> +
> +	/*
> +	 * Verify HEAD
> +	 */
> +	head = resolve_ref_unsafe("HEAD", 0, sha1, &flag);

The last parameter is a set of flag bits, so call it flags.

> +	if (!head) {
> +		if (get_sha1("HEAD", sha1)) {
> +			string_list_clear(&revs, 0);
> +			string_list_clear(&states, 0);
> +			die(_("Bad HEAD - I need a HEAD"));

We see many repeated calls to clear these two string lists before
exiting with failure, either by dying or return -1.

I wonder how bad the resulting code would look like if we employed
the standard pattern of having a "fail_return:" label at the end of
the function (after the "return" for the usual control flow) to
clear them.  If the result becomes less readable (and I suspect that
you would end up making it less readable), leaving the current code
structure is OK.

> +		}
> +	}
> +	if (!is_empty_or_missing_file(git_path_bisect_start())) {
> +		/* Reset to the rev from where we started */
> +		strbuf_read_file(&start_head, git_path_bisect_start(), 0);
> +		strbuf_trim(&start_head);
> +		if (!no_checkout) {
> +			struct argv_array argv = ARGV_ARRAY_INIT;
> +			argv_array_pushl(&argv, "checkout", start_head.buf,
> +					 "--", NULL);
> +			if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) {
> +				error(_("checking out '%s' failed. Try again."),
> +				      start_head.buf);

The original suggests to try "git bisect reset" here to recover.

> +				strbuf_release(&start_head);
> +				string_list_clear(&revs, 0);
> +				string_list_clear(&states, 0);
> +				return -1;
> +			}
> +		}
> +	} else {
> +		if (starts_with(head, "refs/head/") || !get_oid(head, &oid)) {

get_oid() is insufficient to ensure what you have in $head is
40-hex.  I think you meant get_oid_hex() here.

> +			/*
> +			 * This error message should only be triggered by
> +			 * cogito usage, and cogito users should understand
> +			 * it relates to cg-seek.
> +			 */
> +			if (!is_empty_or_missing_file(git_path_head_name())) {
> +				strbuf_release(&start_head);
> +				string_list_clear(&revs, 0);
> +				string_list_clear(&states, 0);
> +				die(_("won't bisect on cg-seek'ed tree"));
> +			}
> +			if (starts_with(head, "refs/heads/")) {

skip_prefix(), perhaps, if "head" is no longer used from here on?

> +	/*
> +	 * Write new start state
> +	 */
> +	fp = fopen(git_path_bisect_start(), "w");
> +	if (!fp) {
> +		bisect_clean_state();
> +		strbuf_release(&start_head);
> +		string_list_clear(&revs, 0);
> +		string_list_clear(&states, 0);
> +		return -1;
> +	}
> +	if (!fprintf(fp, "%s\n", start_head.buf)) {

man 3 fprintf and look for "Return Value"?

> +		fclose(fp);
> +		bisect_clean_state();
> +		strbuf_release(&start_head);
> +		string_list_clear(&revs, 0);
> +		string_list_clear(&states, 0);
> +		return -1;
> +	}
> +	fclose(fp);

Perhaps use write_file() instead of the above block of text?

> +	if (no_checkout) {
> +		get_oid(start_head.buf, &oid);
> +		if (update_ref(NULL, "BISECT_HEAD", oid.hash, NULL, 0,
> +			       UPDATE_REFS_MSG_ON_ERR)) {

Doesn't the original use --no-deref for this update-ref call?

> +			bisect_clean_state();
> +			strbuf_release(&start_head);
> +			string_list_clear(&revs, 0);
> +			string_list_clear(&states, 0);
> +			return -1;
> +		}
> +	}
> +	strbuf_release(&start_head);
> +	fp = fopen(git_path_bisect_names(), "w");
> +
> +	for (; i < argc; i++) {
> +		if (!fprintf(fp, "%s ", argv[i])) {

man 3 fprintf and look for "Return Value"?

More importantly, the original does --sq-quote so that BISECT_NAMES
file can be read back by a shell.  This is important as argv[i] can
have whitespace in it, and you are concatenating them with SP in
between here.  Also you are not terminating that line.

> +			fclose(fp);
> +			bisect_clean_state();
> +			string_list_clear(&revs, 0);
> +			string_list_clear(&states, 0);
> +			return -1;
> +		}
> +	}
> +	fclose(fp);

Perhaps

	strbuf_reset(&bisect_names);
	if (pathspec_pos < argc)
		sq_quote_argv(&bisect_names, argv + pathspec_pos, 0);
	write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);

or something like that?

> +	for (j = 0; j < states.nr; j ++) {

Again, is "i" still precious here?  Style: drop SP between j and ++.

> +	fp = fopen(git_path_bisect_log(), "a");
> +	if (!fp) {
> +		bisect_clean_state();
> +		return -1;
> +	}
> +	if (!fprintf(fp, "git bisect start")) {
> +		bisect_clean_state();
> +		return -1;
> +	}
> +	for (i = 0; i < argc; i++) {
> +		if (!fprintf(fp, " '%s'", argv[i])) {
> +			fclose(fp);
> +			bisect_clean_state();
> +			return -1;
> +		}
> +	}
> +	if (!fprintf(fp, "\n")) {
> +		fclose(fp);
> +		bisect_clean_state();
> +		return -1;
> +	}

Again, the original writes orig_args which was protected with --sq-quote.

> +	fclose(fp);
> +
> +	return 0;
> +}
> +

^ permalink raw reply	[relevance 5%]

* [PATCH] Makefile: use VCSSVN_LIB to refer to svn library
  2016-07-01  7:56  5% [PATCH] Makefile: drop extra dependencies for test helpers Jeff King
@ 2016-07-01  7:59  5% ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2016-07-01  7:59 UTC (permalink / raw)
  To: git

We have an abstracted variable; let's use it consistently.

Signed-off-by: Jeff King <peff@peff.net>
---
On top of the cleanup earlier in the thread.

I actually wonder if we should drop the vcs-svn code entirely. The last
update that wasn't just part of a "I'm grepping the whole code base to
change this interface" patch was almost 4 years ago, and AFAICT it never
reached a shippable point (we _do_ actually install git-remote-testsvn,
but given the name, I sort of assume nobody is using it).

But I don't want to step on the toes of anybody who actually is using
it, or is planning to work on it more.

 Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 22815a2..4579eab 100644
--- a/Makefile
+++ b/Makefile
@@ -2225,9 +2225,9 @@ perf: all
 
 .PHONY: test perf
 
-t/helper/test-line-buffer$X: vcs-svn/lib.a
+t/helper/test-line-buffer$X: $(VCSSVN_LIB)
 
-t/helper/test-svn-fe$X: vcs-svn/lib.a
+t/helper/test-svn-fe$X: $(VCSSVN_LIB)
 
 .PRECIOUS: $(TEST_OBJS)
 
-- 
2.9.0.317.g65b4e7c

^ permalink raw reply related	[relevance 5%]

* [PATCH] Makefile: drop extra dependencies for test helpers
@ 2016-07-01  7:56  5% Jeff King
  2016-07-01  7:59  5% ` [PATCH] Makefile: use VCSSVN_LIB to refer to svn library Jeff King
  0 siblings, 1 reply; 200+ results
From: Jeff King @ 2016-07-01  7:56 UTC (permalink / raw)
  To: git

A few test-helpers have Makefile dependencies on specific
object files. But since these files are part of libgit.a
(which all of the helpers link against), the inclusion is
simply redundant.

These were once necessary, but became redundant due to
5c5ba73 (Makefile: Use generic rule to build test programs,
2007-05-31), which added the $(GITLIBS) dependency (but
didn't prune the extra dependency lines). Later commits then
cargo-culted the practice (e.g., b4285c7).

Note that we _do_ need to leave the dependencies on the svn
library, as that is not part of the usual link command.

Signed-off-by: Jeff King <peff@peff.net>
---
Just a cleanup I noticed while working on the common-main series.

 Makefile | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/Makefile b/Makefile
index de5a030..22815a2 100644
--- a/Makefile
+++ b/Makefile
@@ -2225,16 +2225,8 @@ perf: all
 
 .PHONY: test perf
 
-t/helper/test-ctype$X: ctype.o
-
-t/helper/test-date$X: date.o ctype.o
-
-t/helper/test-delta$X: diff-delta.o patch-delta.o
-
 t/helper/test-line-buffer$X: vcs-svn/lib.a
 
-t/helper/test-parse-options$X: parse-options.o parse-options-cb.o
-
 t/helper/test-svn-fe$X: vcs-svn/lib.a
 
 .PRECIOUS: $(TEST_OBJS)
-- 
2.9.0.317.g65b4e7c

^ permalink raw reply related	[relevance 5%]

* Re: 'untracked working tree files would be overwritten by merge' on ignored files?
  @ 2016-06-14 17:06  4% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2016-06-14 17:06 UTC (permalink / raw)
  To: Andreas Krey; +Cc: git

Andreas Krey <a.krey@gmx.de> writes:

> when I have an ignored file in my workspace, is git
> then also assumed not to remove it in the course
> of a merge?

IIRC, untracked files are kept during merge and across checking out
another branch.  Files that are deliberately marked as ignored by
listing them to .gitignore mechanism are considered expendable, and
they will be removed as necessary.

This is because we do not have the fourth-class, "we do not want to
add them to the history as tracked contents, but we do not want to
lose them", aka "precious"; we only have three, i.e. "paths in the
index", "path that are untracked" and "path that are ignored".

^ permalink raw reply	[relevance 4%]

* Re: Repacking a repository uses up all available disk space
  2016-06-13  0:24  4%       ` Duy Nguyen
@ 2016-06-13  4:58  0%         ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2016-06-13  4:58 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Konstantin Ryabitsev, Git Mailing List

On Mon, Jun 13, 2016 at 07:24:51AM +0700, Duy Nguyen wrote:

> >> - git fsck --full
> >> - git repack -Adl -b --pack-kept-objects
> >> - git pack-refs --all
> >> - git prune
> >>
> >> The reason it's split into repack + prune instead of just gc is because
> >> we use alternates to save on disk space and try not to prune repos that
> >> are used as alternates by other repos in order to avoid potential
> >> corruption.
> 
> Isn't this what extensions.preciousObjects is for? It looks like prune
> just refuses to run in precious objects mode though, and repack is
> skipped by gc, but if that repack command works, maybe we should do
> something like that in git-gc?

Sort of. preciousObjects is a fail-safe so that you do not ever
accidentally run an object-deleting operation where you shouldn't (e.g.,
in the shared repository used by others as an alternate). So the
important step there is that before running "repack", you would want to
make sure you have taken into account the reachability of anybody
sharing from you.

So you could do something like (in your shared repository):

  git config core.repositoryFormatVersion 1
  git config extension.preciousObjects true

  # this will fail, because it's dangerous!
  git gc

  # but we can do it safely if we take into account the other repos
  for repo in $(somehow_get_list_of_shared_repos); do
	git fetch $repo +refs/*:refs/shared/$repo/*
  done
  git config extension.preciousObjects false
  git gc
  git config extension.preciousObjects true

So it really is orthogonal to running the various gc commands yourself;
it's just here to prevent you shooting yourself in the foot.

It may still be useful in such a case to split up the commands in your
own script, though. In my case, you'll note that the commands above are
racy (what happens if somebody pushes a reference to a shared object
between your fetch and the gc invocation?). So we use a custom "repack
-k" to get around that (it just keeps everything).

You _could_ have gc automatically switch to "-k" in a preciousObjects
repository. That's at least safe. But note that it doesn't really solve
all of the problems (you do still want to have ref tips from the leaf
repositories, because it affects things like bitmaps, and packing
order).

> BTW Jeff, I think we need more documentation for
> extensions.preciousObjects. It's only documented in technical/ which
> is practically invisible to all users. Maybe
> include::repository-version.txt in config.txt, or somewhere close to
> alternates?

I'm a little hesitant to document it for end users because it's still
pretty experimental. In fact, even we are not using it at GitHub
currently. We don't have a big problem with "oops, I accidentally ran
something destructive in the shared repository", because nothing except
the maintenance script ever even goes into the shared repository.

The reason I introduced it in the first place is that I was
experimenting with the idea of actually symlinking "objects/" in the
leaf repos into the shared repository. That eliminates the object
writing in the "fetch" step above, which can be a bottleneck in some
cases (not just the I/O, but the shared repo ends up having a _lot_ of
refs, and fetch can be pretty slow).

But in that case, anything that deletes an object in one of the leaf
repos is very dangerous, as it has no idea that its object store is
shared with other leaf repos. So I really wanted a fail safe so that
running "git gc" wasn't catastrophic.

I still think that's a viable approach, but my experiments got
side-tracked and I never produced anything worth looking at. So until
there's something end users can actually make use of, I'm hesitant to
push that stuff into the regular-user documentation. Anybody who is
playing with it at this point probably _should_ be familiar with what's
in Documentation/technical.

-Peff

^ permalink raw reply	[relevance 0%]

* [PATCH 2/3] repack: add --keep-unreachable option
  @ 2016-06-13  4:36  4% ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2016-06-13  4:36 UTC (permalink / raw)
  To: Nasser Grainawi; +Cc: Konstantin Ryabitsev, git, Junio C Hamano

The usual way to do a full repack (and what is done by
git-gc) is to run "repack -Ad --unpack-unreachable=<when>",
which will loosen any unreachable objects newer than
"<when>", and drop any older ones.

This is a safer alternative to "repack -ad", because
"<when>" becomes a grace period during which we will not
drop any new objects that are about to be referenced.
However, it isn't perfectly safe. It's always possible that
a process is about to reference an old object. Even if that
process were to take care to update the timestamp on the
object, there is no atomicity with a simultaneously running
"repack" process.

So while unlikely, there is a small race wherein we may drop
an object that is in the process of being referenced. If you
do automated repacking on a large number of active
repositories, you may hit it eventually, and the result is a
corrupted repository.

It would be nice to fix that race in the long run, but it's
complicated.  In the meantime, there is a much simpler
strategy for automated repository maintenance: do not drop
objects at all. We already have a "--keep-unreachable"
option in pack-objects; we just need to plumb it through
from git-repack.

Note that this _isn't_ plumbed through from git-gc, so at
this point it's strictly a tool for people doing their own
advanced repository maintenance strategy.

Signed-off-by: Jeff King <peff@peff.net>
---
 Documentation/git-repack.txt         |  6 ++++++
 builtin/repack.c                     |  9 +++++++++
 t/t7701-repack-unpack-unreachable.sh | 15 +++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index cde7b44..68702ea 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -134,6 +134,12 @@ other objects in that pack they already have locally.
 	the write of any objects that would be immediately pruned by
 	a follow-up `git prune`.
 
+-k::
+--keep-unreachable::
+	When used with `-ad`, any unreachable objects from existing
+	packs will be appended to the end of the packfile instead of
+	being removed.
+
 Configuration
 -------------
 
diff --git a/builtin/repack.c b/builtin/repack.c
index 858db38..573e66c 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -146,6 +146,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	int pack_everything = 0;
 	int delete_redundant = 0;
 	const char *unpack_unreachable = NULL;
+	int keep_unreachable = 0;
 	const char *window = NULL, *window_memory = NULL;
 	const char *depth = NULL;
 	const char *max_pack_size = NULL;
@@ -175,6 +176,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 				N_("write bitmap index")),
 		OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
 				N_("with -A, do not loosen objects older than this")),
+		OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
+				N_("with -a, repack unreachable objects")),
 		OPT_STRING(0, "window", &window, N_("n"),
 				N_("size of the window used for delta compression")),
 		OPT_STRING(0, "window-memory", &window_memory, N_("bytes"),
@@ -196,6 +199,10 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 	if (delete_redundant && repository_format_precious_objects)
 		die(_("cannot delete packs in a precious-objects repo"));
 
+	if (keep_unreachable &&
+	    (unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE)))
+		die(_("--keep-unreachable and -A are incompatible"));
+
 	if (pack_kept_objects < 0)
 		pack_kept_objects = write_bitmaps;
 
@@ -239,6 +246,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 			} else if (pack_everything & LOOSEN_UNREACHABLE) {
 				argv_array_push(&cmd.args,
 						"--unpack-unreachable");
+			} else if (keep_unreachable) {
+				argv_array_push(&cmd.args, "--keep-unreachable");
 			} else {
 				argv_array_push(&cmd.env_array, "GIT_REF_PARANOIA=1");
 			}
diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh
index b66e383..f13df43 100755
--- a/t/t7701-repack-unpack-unreachable.sh
+++ b/t/t7701-repack-unpack-unreachable.sh
@@ -122,4 +122,19 @@ test_expect_success 'keep packed objects found only in index' '
 	git cat-file blob :file
 '
 
+test_expect_success 'repack -k keeps unreachable packed objects' '
+	# create packed-but-unreachable object
+	sha1=$(echo unreachable-packed | git hash-object -w --stdin) &&
+	pack=$(echo $sha1 | git pack-objects .git/objects/pack/pack) &&
+	git prune-packed &&
+
+	# -k should keep it
+	git repack -adk &&
+	git cat-file -p $sha1 &&
+
+	# and double check that without -k it would have been removed
+	git repack -ad &&
+	test_must_fail git cat-file -p $sha1
+'
+
 test_done
-- 
2.9.0.rc2.149.gd580ccd

^ permalink raw reply related	[relevance 4%]

* Re: Repacking a repository uses up all available disk space
  @ 2016-06-13  0:24  4%       ` Duy Nguyen
  2016-06-13  4:58  0%         ` Jeff King
  0 siblings, 1 reply; 200+ results
From: Duy Nguyen @ 2016-06-13  0:24 UTC (permalink / raw)
  To: Jeff King; +Cc: Konstantin Ryabitsev, Git Mailing List

On Mon, Jun 13, 2016 at 5:13 AM, Jeff King <peff@peff.net> wrote:
> On Sun, Jun 12, 2016 at 05:54:36PM -0400, Konstantin Ryabitsev wrote:
>
>> >   git gc --prune=now
>>
>> You are correct, this solves the problem, however I'm curious. The usual
>> maintenance for these repositories is a regular run of:
>>
>> - git fsck --full
>> - git repack -Adl -b --pack-kept-objects
>> - git pack-refs --all
>> - git prune
>>
>> The reason it's split into repack + prune instead of just gc is because
>> we use alternates to save on disk space and try not to prune repos that
>> are used as alternates by other repos in order to avoid potential
>> corruption.

Isn't this what extensions.preciousObjects is for? It looks like prune
just refuses to run in precious objects mode though, and repack is
skipped by gc, but if that repack command works, maybe we should do
something like that in git-gc?

BTW Jeff, I think we need more documentation for
extensions.preciousObjects. It's only documented in technical/ which
is practically invisible to all users. Maybe
include::repository-version.txt in config.txt, or somewhere close to
alternates?

> [2] It's unclear to me if you're passing any options to git-prune, but
>     you may want to pass "--expire" with a short grace period. Without
>     any options it prunes every unreachable thing, which can lead to
>     races if the repository is actively being used.
>
>     At GitHub we actually have a patch to `repack` that keeps all
>     objects, reachable or not, in the pack, and use it for all of our
>     automated maintenance. Since we don't drop objects at all, we can't
>     ever have such a race. Aside from some pathological cases, it wastes
>     much less space than you'd expect. We turn the flag off for special
>     cases (e.g., somebody has rewound history and wants to expunge a
>     sensitive object).
>
>     I'm happy to share the "keep everything" patch if you're interested.

Ah ok, I guess this is why we just skip repack. I guess '-Adl -b
--pack-kept-objects' is not enough then.
-- 
Duy

^ permalink raw reply	[relevance 4%]

* [PATCH v2 28/33] ref_transaction_update(): check refname_is_safe() at a minimum
  @ 2016-05-06 16:14  5% ` Michael Haggerty
  0 siblings, 0 replies; 200+ results
From: Michael Haggerty @ 2016-05-06 16:14 UTC (permalink / raw)
  To: Junio C Hamano, David Turner
  Cc: Jeff King, Nguyễn Thái Ngọc Duy, Ramsay Jones,
	git, Michael Haggerty

If the user has asked that a new value be set for a reference, we use
check_refname_format() to verify that the reference name satisfies all
of the rules. But in other cases, at least check that refname_is_safe().

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 refs.c                  | 5 +++--
 t/t1400-update-ref.sh   | 2 +-
 t/t1430-bad-ref-name.sh | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index 7c4eeb1..842c5c7 100644
--- a/refs.c
+++ b/refs.c
@@ -805,8 +805,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
 {
 	assert(err);
 
-	if (new_sha1 && !is_null_sha1(new_sha1) &&
-	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+	if ((new_sha1 && !is_null_sha1(new_sha1)) ?
+	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
+	    !refname_is_safe(refname)) {
 		strbuf_addf(err, "refusing to update ref with bad name '%s'",
 			    refname);
 		return -1;
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 40b0cce..08bd8fd 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -23,7 +23,7 @@ test_expect_success setup '
 m=refs/heads/master
 n_dir=refs/heads/gu
 n=$n_dir/fixes
-outside=foo
+outside=refs/foo
 
 test_expect_success \
 	"create $m" \
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index 25ddab4..8937e25 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -285,7 +285,7 @@ test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
 	echo precious >expect &&
 	test_must_fail git update-ref -d my-private-file >output 2>error &&
 	test_must_be_empty output &&
-	test_i18ngrep -e "cannot lock .*: unable to resolve reference" error &&
+	test_i18ngrep -e "refusing to update ref with bad name" error &&
 	test_cmp expect .git/my-private-file
 '
 
-- 
2.8.1

^ permalink raw reply related	[relevance 5%]

* Re: git status core dump with bad sector!
  2016-04-22  5:11  0% ` Jeff King
@ 2016-05-04 20:37  0%   ` Eric Chamberland
  0 siblings, 0 replies; 200+ results
From: Eric Chamberland @ 2016-05-04 20:37 UTC (permalink / raw)
  To: Jeff King; +Cc: git@vger.kernel.org

Hi,

sorry for the delay...

On 22/04/16 01:11 AM, Jeff King wrote:
> On Thu, Apr 14, 2016 at 10:59:57AM -0400, Eric Chamberland wrote:
>
>> just cloned a repo and it checked-out wihtout any error (with git 2.2.0) but
>> got come corrupted files (because I got some sdd failures).
>>
>> Then, I get a git core dump when trying to "git status" into the repo which
>> have a "bad sector" on sdd drive (crypted partition).
>>
>> I tried with git 2.2.0 AND git version 2.8.1.185.gdc0db2c.dirty (just
>> modified the Makefile to remove STRIP part)
>>
>> In both cases, I have a  Bus error (core dumped)
>
> Interesting. There was a known issue with reading corrupted pack .idx
> files, but it was fixed in v2.8.0. So this could be a new thing.
>
> SIGBUS is somewhat rare, though (usually just accessing unmapped memory
> should get us a SIGSEGV). What platform are you on? I seem to recall
> that hardware like ARM that cares about memory alignment is more likely
> to get a SIGBUS.
>
Linux ... 3.7.10-1.45-desktop #1 SMP PREEMPT Tue Dec 16 20:27:58 UTC 
2014 (4c885a1) x86_64 x86_64 x86_64 GNU/Linux
df .
Filesystem                                     1K-blocks      Used 
Available Use% Mounted on
/dev/mapper/cr_ata-ST31000524AS_6VPCXHSW-part1 961430856 699476812 
213116108  77% /pmi

model name      : Intel(R) Xeon(R) CPU           X5690  @ 3.47GHz

>> Program received signal SIGBUS, Bus error.
>> 0x00007ffff7866d58 in ?? () from /lib64/libcrypto.so.1.0.0
>> (gdb) bt
>> #0  0x00007ffff7866d58 in ?? () from /lib64/libcrypto.so.1.0.0
>> #1  0x3334d90d8c20f3f0 in ?? ()
>> #2  0xe59b5a6cd844a601 in ?? ()
>> #3  0xc587a53f67985ae7 in ?? ()
>> #4  0x3ce81893e5541777 in ?? ()
>> #5  0xdeb18349a4b042ea in ?? ()
>> #6  0x8254de489067ec4b in ?? ()
>> #7  0x6fbef2439704c81b in ?? ()
>> #8  0xe0eee2bb385a96da in ?? ()
>> #9  0x00007ffff6e19ab3 in ?? ()
>> #10 0x00007fffffffc4d0 in ?? ()
>> #11 0x000000000000001d in ?? ()
>> #12 0x00007ffff7863f80 in SHA1_Update () from /lib64/libcrypto.so.1.0.0
>> #13 0x00000000005102c0 in write_sha1_file_prepare
>> (buf=buf@entry=0x7ffff6c81000, len=1673936, type=<optimized out>,
>> sha1=sha1@entry=0x7fffffffc750 "\340_~", hdr=hdr@entry=0x7fffffffc570 "blob
>> 1673936",
>
> So I'd assume here that the problem is in accessing the memory in "buf".
> to actually compute the sha1. That is mmap'd data, but the process is
> fairly bland (mmap however many bytes stat() tells us the file has, and
> then compute the sha1). You mentioned a bad sector; could it be that the
> filesystem is corrupted, and the OS is giving us SIGBUS when trying to
> read unavailable bytes from an mmap'd file?

Yes it could be that...

>
> That would explain the SIGBUS versus SIGSEGV.
>
> What happens if you "cat" the file in question:

hmmm, it shows the beginning of the file, then ends with:

cat: Avion.Quadratique.cont.vtu.etalon: Input/output error

also, this appear in /var/log/messages:

2016-05-04T16:33:19.243595-04:00 melkor kernel: [1096660.854161] 
ata4.00: exception Emask 0x0 SAct 0x1 SErr 0x0 action 0x0
2016-05-04T16:33:19.243609-04:00 melkor kernel: [1096660.854165] 
ata4.00: irq_stat 0x40000008
2016-05-04T16:33:19.243610-04:00 melkor kernel: [1096660.854168] 
ata4.00: failed command: READ FPDMA QUEUED
2016-05-04T16:33:19.243611-04:00 melkor kernel: [1096660.854175] 
ata4.00: cmd 60/08:00:70:30:c6/00:00:53:00:00/40 tag 0 ncq 4096 in
2016-05-04T16:33:19.243612-04:00 melkor kernel: [1096660.854175] 
   res 41/40:08:71:30:c6/00:00:53:00:00/00 Emask 0x409 (media error) <F>
2016-05-04T16:33:19.243613-04:00 melkor kernel: [1096660.854178] 
ata4.00: status: { DRDY ERR }
2016-05-04T16:33:19.243614-04:00 melkor kernel: [1096660.854180] 
ata4.00: error: { UNC }
2016-05-04T16:33:19.340479-04:00 melkor kernel: [1096660.950794] 
ata4.00: configured for UDMA/133
2016-05-04T16:33:19.340484-04:00 melkor kernel: [1096660.950806] sd 
3:0:0:0: [sdb] Unhandled sense code
2016-05-04T16:33:19.340485-04:00 melkor kernel: [1096660.950809] sd 
3:0:0:0: [sdb]
2016-05-04T16:33:19.340485-04:00 melkor kernel: [1096660.950811] Result: 
hostbyte=DID_OK driverbyte=DRIVER_SENSE
2016-05-04T16:33:19.340486-04:00 melkor kernel: [1096660.950814] sd 
3:0:0:0: [sdb]
2016-05-04T16:33:19.340486-04:00 melkor kernel: [1096660.950815] Sense 
Key : Medium Error [current] [descriptor]
2016-05-04T16:33:19.340486-04:00 melkor kernel: [1096660.950819] 
Descriptor sense data with sense descriptors (in hex):
2016-05-04T16:33:19.340487-04:00 melkor kernel: [1096660.950820] 
  72 03 11 04 00 00 00 0c 00 0a 80 00 00 00 00 00
2016-05-04T16:33:19.340487-04:00 melkor kernel: [1096660.950829] 
  53 c6 30 71
2016-05-04T16:33:19.340488-04:00 melkor kernel: [1096660.950834] sd 
3:0:0:0: [sdb]
2016-05-04T16:33:19.340488-04:00 melkor kernel: [1096660.950836] Add. 
Sense: Unrecovered read error - auto reallocate failed
2016-05-04T16:33:19.340489-04:00 melkor kernel: [1096660.950839] sd 
3:0:0:0: [sdb] CDB:
2016-05-04T16:33:19.340489-04:00 melkor kernel: [1096660.950840] 
Read(10): 28 00 53 c6 30 70 00 00 08 00
2016-05-04T16:33:19.340489-04:00 melkor kernel: [1096660.950848] 
end_request: I/O error, dev sdb, sector 1405497457
2016-05-04T16:33:19.340490-04:00 melkor kernel: [1096660.950870] ata4: 
EH complete
2016-05-04T16:33:22.157550-04:00 melkor kernel: [1096663.764515] 
ata4.00: exception Emask 0x0 SAct 0x1 SErr 0x0 action 0x0
2016-05-04T16:33:22.157561-04:00 melkor kernel: [1096663.764519] 
ata4.00: irq_stat 0x40000008
2016-05-04T16:33:22.157563-04:00 melkor kernel: [1096663.764522] 
ata4.00: failed command: READ FPDMA QUEUED
2016-05-04T16:33:22.157564-04:00 melkor kernel: [1096663.764529] 
ata4.00: cmd 60/08:00:70:30:c6/00:00:53:00:00/40 tag 0 ncq 4096 in
2016-05-04T16:33:22.157565-04:00 melkor kernel: [1096663.764529] 
   res 41/40:08:71:30:c6/00:00:53:00:00/00 Emask 0x409 (media error) <F>
2016-05-04T16:33:22.157566-04:00 melkor kernel: [1096663.764532] 
ata4.00: status: { DRDY ERR }
2016-05-04T16:33:22.157567-04:00 melkor kernel: [1096663.764534] 
ata4.00: error: { UNC }
2016-05-04T16:33:22.180479-04:00 melkor kernel: [1096663.787215] 
ata4.00: configured for UDMA/133
2016-05-04T16:33:22.180485-04:00 melkor kernel: [1096663.787225] sd 
3:0:0:0: [sdb] Unhandled sense code
2016-05-04T16:33:22.180486-04:00 melkor kernel: [1096663.787228] sd 
3:0:0:0: [sdb]
2016-05-04T16:33:22.180486-04:00 melkor kernel: [1096663.787230] Result: 
hostbyte=DID_OK driverbyte=DRIVER_SENSE
2016-05-04T16:33:22.180487-04:00 melkor kernel: [1096663.787232] sd 
3:0:0:0: [sdb]
2016-05-04T16:33:22.180487-04:00 melkor kernel: [1096663.787234] Sense 
Key : Medium Error [current] [descriptor]
2016-05-04T16:33:22.180487-04:00 melkor kernel: [1096663.787237] 
Descriptor sense data with sense descriptors (in hex):
2016-05-04T16:33:22.180488-04:00 melkor kernel: [1096663.787238] 
  72 03 11 04 00 00 00 0c 00 0a 80 00 00 00 00 00
2016-05-04T16:33:22.180488-04:00 melkor kernel: [1096663.787247] 
  53 c6 30 71
2016-05-04T16:33:22.180489-04:00 melkor kernel: [1096663.787252] sd 
3:0:0:0: [sdb]
2016-05-04T16:33:22.180489-04:00 melkor kernel: [1096663.787254] Add. 
Sense: Unrecovered read error - auto reallocate failed
2016-05-04T16:33:22.180490-04:00 melkor kernel: [1096663.787256] sd 
3:0:0:0: [sdb] CDB:
2016-05-04T16:33:22.180490-04:00 melkor kernel: [1096663.787258] 
Read(10): 28 00 53 c6 30 70 00 00 08 00
2016-05-04T16:33:22.180490-04:00 melkor kernel: [1096663.787266] 
end_request: I/O error, dev sdb, sector 1405497457
2016-05-04T16:33:22.180491-04:00 melkor kernel: [1096663.787280] ata4: 
EH complete


>
>> #15 0x00000000005159f8 in index_mem (sha1=sha1@entry=0x7fffffffc750
>> "\340_~", buf=buf@entry=0x7ffff6c81000, size=1673936,
>> type=type@entry=OBJ_BLOB,
>>      path=path@entry=0x80a818 "Ressources/dev/Test.ExportationVTK/Ressources.Avion/Avion.Quadratique.cont.vtu.etalon",
>> flags=flags@entry=0) at sha1_file.c:3305
>
> Can it show all of the bytes? I guess from the "size" field it's too big
> to manually verify, but "cat >/dev/null" should be enough to see if we
> can read the whole thing.
>
>> Ii would have expected git to first gave me an error when checking out the
>> files!!! Here is the log:
>>
>> Checking out files:  99% (28645/28934)
>> Checking out files: 100% (28934/28934)
>> Checking out files: 100% (28934/28934), done.
>> Already on 'master'
>> Your branch is up-to-date with 'origin/master'.
>>      On valide le dépôt TestValidation avec la référence:
>> 9b4a485202b2b52922377842c15bfd605d240667
>> HEAD is now at 9b4a485 BUG: On spécifie bash comme shell...
>>
>> But at least 1 file is corrupted!
>>
>> I keep preciously this faulty repo to further investigation with someone who
>> can help dig into the coredump and correct it...
>
> So _if_ my guess is right that you have filesystem corruption, git may
> not even know about it. It wrote the file, and the OS said "OK,
> success", not knowing it had been partially corrupted.

ok, I see...
>
> And if that guess is right, it also means there's no git bug to fix.
> SIGBUS is the natural way for the OS to tell the process that mmap'd
> data isn't available.

doh... then forget about this...

Thanks for the enlightments! :)

Eric
>
> -Peff
>

^ permalink raw reply	[relevance 0%]

* Re: [PATCH] Move test-* to t/helper/ subdirectory
  @ 2016-05-01  0:28  4%         ` Duy Nguyen
  0 siblings, 0 replies; 200+ results
From: Duy Nguyen @ 2016-05-01  0:28 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

On Wed, Apr 27, 2016 at 09:15:41AM -0700, Junio C Hamano wrote:
> Duy Nguyen <pclouds@gmail.com> writes:
> 
> > This patch forces bin-wrappers regeneration every time a test program
> > is updated. A bit wasteful, but I don't see a better option (which is
> > also why I limit this to test programs only).
> 
> In other words, when we update the location where the programs that
> would be eventually installed are created, we'd see the same
> problem.
> 
> I actually wonder if it is a better overall structure to move
> t/helper/test-foo back to test-foo, while keeping the source file
> that contains main() for test-foo at t/helper/test-foo.c.  Then we
> do not have to have many copies that are slightly different in
> bin-wrappers, but they can all be
> 
> 	exec "${GIT_EXEC_PATH}/$0" "$@"
> 
> instead of "bin-wrappers/git-bar" being
> 
> 	exec "${GIT_EXEC_PATH}/git-bar" "$@"
> 
> and "bin-wrappers/test-foo" being
> 
> 	exec "${GIT_EXEC_PATH}/t/helper/test-foo" "$@"
> 

It's not a perfect solution (rebuild bin-wrappers when the real binary
moves) but I think it's the best option so far. We can move test-*
binaries back with this patch.

-- 8< --
diff --git a/.gitignore b/.gitignore
index 05cb58a..5087ce1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,6 +179,39 @@
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
 /gitweb/static/gitweb.min.*
+/test-chmtime
+/test-ctype
+/test-config
+/test-date
+/test-delta
+/test-dump-cache-tree
+/test-dump-split-index
+/test-dump-untracked-cache
+/test-fake-ssh
+/test-scrap-cache-tree
+/test-genrandom
+/test-hashmap
+/test-index-version
+/test-line-buffer
+/test-match-trees
+/test-mergesort
+/test-mktemp
+/test-parse-options
+/test-path-utils
+/test-prio-queue
+/test-read-cache
+/test-regex
+/test-revision-walking
+/test-run-command
+/test-sha1
+/test-sha1-array
+/test-sigchain
+/test-string-list
+/test-submodule-config
+/test-subprocess
+/test-svn-fe
+/test-urlmatch-normalization
+/test-wildmatch
 /common-cmds.h
 *.tar.gz
 *.dsc
diff --git a/Makefile b/Makefile
index dd178ee..7a1c973 100644
--- a/Makefile
+++ b/Makefile
@@ -620,7 +620,7 @@ TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
 TEST_PROGRAMS_NEED_X += test-wildmatch
 
-TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
+TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
 
 # List built-in command $C whose implementation cmd_$C() is not in
 # builtin/$C.o but is linked in as part of some other command.
@@ -1897,7 +1897,7 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
 VCSSVN_OBJS += vcs-svn/svndiff.o
 VCSSVN_OBJS += vcs-svn/svndump.o
 
-TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
+TEST_OBJS := $(patsubst %,t/helper/%.o,$(TEST_PROGRAMS_NEED_X))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
 	$(VCSSVN_OBJS) \
@@ -2204,7 +2204,7 @@ bin-wrappers/%: wrap-for-bin.sh
 	@mkdir -p bin-wrappers
 	$(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
 	     -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
-	     -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))|' < $< > $@ && \
+	     -e 's|@@PROG@@|$(@F)|'< $< > $@ && \
 	chmod +x $@
 
 # GNU make supports exporting all variables by "export" without parameters.
@@ -2224,24 +2224,24 @@ perf: all
 
 .PHONY: test perf
 
-t/helper/test-ctype$X: ctype.o
+test-ctype$X: ctype.o
 
-t/helper/test-date$X: date.o ctype.o
+test-date$X: date.o ctype.o
 
-t/helper/test-delta$X: diff-delta.o patch-delta.o
+test-delta$X: diff-delta.o patch-delta.o
 
-t/helper/test-line-buffer$X: vcs-svn/lib.a
+test-line-buffer$X: vcs-svn/lib.a
 
-t/helper/test-parse-options$X: parse-options.o parse-options-cb.o
+test-parse-options$X: parse-options.o parse-options-cb.o
 
-t/helper/test-svn-fe$X: vcs-svn/lib.a
+test-svn-fe$X: vcs-svn/lib.a
 
 .PRECIOUS: $(TEST_OBJS)
 
-t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
+test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
-check-sha1:: t/helper/test-sha1$X
+check-sha1:: test-sha1$X
 	t/helper/test-sha1.sh
 
 SP_OBJ = $(patsubst %.o,%.sp,$(C_OBJ))
diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh
index 750b95a..cef4bcc 100755
--- a/t/helper/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 dd if=/dev/zero bs=1048576 count=100 2>/dev/null |
-/usr/bin/time t/helper/test-sha1 >/dev/null
+/usr/bin/time ./test-sha1 >/dev/null
 
 while read expect cnt pfx
 do
@@ -11,7 +11,7 @@ do
 			test -z "$pfx" || echo "$pfx"
 			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
 			perl -pe 'y/\000/g/'
-		} | ./t/helper/test-sha1 $cnt
+		} | ./test-sha1 $cnt
 	)
 	if test "$expect" = "$actual"
 	then
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 150aeaf..c1efb8e 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -308,7 +308,7 @@ test_expect_success 'clone checking out a tag' '
 
 setup_ssh_wrapper () {
 	test_expect_success 'setup ssh wrapper' '
-		cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \
+		cp "$GIT_BUILD_DIR/test-fake-ssh$X" \
 			"$TRASH_DIRECTORY/ssh-wrapper$X" &&
 		GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" &&
 		export GIT_SSH &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cd0ecd4..0b47eb6 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -854,10 +854,10 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
 	error "You haven't built things yet, have you?"
 }
 
-if ! test -x "$GIT_BUILD_DIR"/t/helper/test-chmtime
+if ! test -x "$GIT_BUILD_DIR"/test-chmtime
 then
 	echo >&2 'You need to build test-chmtime:'
-	echo >&2 'Run "make t/helper/test-chmtime" in the source (toplevel) directory'
+	echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
 	exit 1
 fi
-- 8< --
 

^ permalink raw reply related	[relevance 4%]

* Re: [PATCH 24/29] ref_transaction_update(): check refname_is_safe() at a minimum
  2016-04-27 16:57  5% ` [PATCH 24/29] ref_transaction_update(): check refname_is_safe() at a minimum Michael Haggerty
@ 2016-04-27 20:14  0%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2016-04-27 20:14 UTC (permalink / raw)
  To: Michael Haggerty
  Cc: git, David Turner, Nguyễn Thái Ngọc Duy,
	Jeff King, Ramsay Jones

Michael Haggerty <mhagger@alum.mit.edu> writes:

> If the user has asked that a new value be set for a reference, we use
> check_refname_format() to verify that the reference name satisfies all
> of the rules. But in other cases, at least check that refname_is_safe().

It isn't clear to me what "in other cases" exactly refers to.  A
request to delete a ref would obviously one of those that do not
"ask that a new value be set", but are there other cases?

> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
> ---
> There are remaining problems in this area of the code. For example,
> check_refname_format() is *less* strict than refname_is_safe(). It
> allows almost arbitrary top-level reference names like "foo" and
> "refs". (The latter is especially fun because if you manage to create
> a reference called "refs", Git stops recognizing the directory as a
> Git repository.) On the other hand, some callers call
> check_refname_format() with incomplete reference names (e.g., branch
> names like "master"), so the functions can't be made stricter until
> those callers are changed.
>
> I'll address these problems separately if I find the time.

Thanks.

>  refs.c                  | 5 +++--
>  t/t1400-update-ref.sh   | 2 +-
>  t/t1430-bad-ref-name.sh | 2 +-
>  3 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/refs.c b/refs.c
> index 858b6d7..41eb9e2 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -802,8 +802,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
>  	if ((flags & REF_ISPRUNING) && !(flags & REF_NODEREF))
>  		die("BUG: REF_ISPRUNING set without REF_NODEREF");
>  
> -	if (new_sha1 && !is_null_sha1(new_sha1) &&
> -	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
> +	if ((new_sha1 && !is_null_sha1(new_sha1)) ?
> +	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
> +	    !refname_is_safe(refname)) {
>  		strbuf_addf(err, "refusing to update ref with bad name '%s'",
>  			    refname);
>  		return -1;
> diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
> index 40b0cce..08bd8fd 100755
> --- a/t/t1400-update-ref.sh
> +++ b/t/t1400-update-ref.sh
> @@ -23,7 +23,7 @@ test_expect_success setup '
>  m=refs/heads/master
>  n_dir=refs/heads/gu
>  n=$n_dir/fixes
> -outside=foo
> +outside=refs/foo
>  
>  test_expect_success \
>  	"create $m" \
> diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
> index 25ddab4..8937e25 100755
> --- a/t/t1430-bad-ref-name.sh
> +++ b/t/t1430-bad-ref-name.sh
> @@ -285,7 +285,7 @@ test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
>  	echo precious >expect &&
>  	test_must_fail git update-ref -d my-private-file >output 2>error &&
>  	test_must_be_empty output &&
> -	test_i18ngrep -e "cannot lock .*: unable to resolve reference" error &&
> +	test_i18ngrep -e "refusing to update ref with bad name" error &&
>  	test_cmp expect .git/my-private-file
>  '

^ permalink raw reply	[relevance 0%]

* [PATCH 24/29] ref_transaction_update(): check refname_is_safe() at a minimum
  @ 2016-04-27 16:57  5% ` Michael Haggerty
  2016-04-27 20:14  0%   ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Michael Haggerty @ 2016-04-27 16:57 UTC (permalink / raw)
  To: git, David Turner
  Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy, Jeff King,
	Ramsay Jones, Michael Haggerty

If the user has asked that a new value be set for a reference, we use
check_refname_format() to verify that the reference name satisfies all
of the rules. But in other cases, at least check that refname_is_safe().

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
There are remaining problems in this area of the code. For example,
check_refname_format() is *less* strict than refname_is_safe(). It
allows almost arbitrary top-level reference names like "foo" and
"refs". (The latter is especially fun because if you manage to create
a reference called "refs", Git stops recognizing the directory as a
Git repository.) On the other hand, some callers call
check_refname_format() with incomplete reference names (e.g., branch
names like "master"), so the functions can't be made stricter until
those callers are changed.

I'll address these problems separately if I find the time.

 refs.c                  | 5 +++--
 t/t1400-update-ref.sh   | 2 +-
 t/t1430-bad-ref-name.sh | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/refs.c b/refs.c
index 858b6d7..41eb9e2 100644
--- a/refs.c
+++ b/refs.c
@@ -802,8 +802,9 @@ int ref_transaction_update(struct ref_transaction *transaction,
 	if ((flags & REF_ISPRUNING) && !(flags & REF_NODEREF))
 		die("BUG: REF_ISPRUNING set without REF_NODEREF");
 
-	if (new_sha1 && !is_null_sha1(new_sha1) &&
-	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
+	if ((new_sha1 && !is_null_sha1(new_sha1)) ?
+	    check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
+	    !refname_is_safe(refname)) {
 		strbuf_addf(err, "refusing to update ref with bad name '%s'",
 			    refname);
 		return -1;
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 40b0cce..08bd8fd 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -23,7 +23,7 @@ test_expect_success setup '
 m=refs/heads/master
 n_dir=refs/heads/gu
 n=$n_dir/fixes
-outside=foo
+outside=refs/foo
 
 test_expect_success \
 	"create $m" \
diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index 25ddab4..8937e25 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -285,7 +285,7 @@ test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
 	echo precious >expect &&
 	test_must_fail git update-ref -d my-private-file >output 2>error &&
 	test_must_be_empty output &&
-	test_i18ngrep -e "cannot lock .*: unable to resolve reference" error &&
+	test_i18ngrep -e "refusing to update ref with bad name" error &&
 	test_cmp expect .git/my-private-file
 '
 
-- 
2.8.1

^ permalink raw reply related	[relevance 5%]

* Re: git status core dump with bad sector!
  2016-04-14 14:59  3% git status core dump with bad sector! Eric Chamberland
@ 2016-04-22  5:11  0% ` Jeff King
  2016-05-04 20:37  0%   ` Eric Chamberland
  0 siblings, 1 reply; 200+ results
From: Jeff King @ 2016-04-22  5:11 UTC (permalink / raw)
  To: Eric Chamberland; +Cc: git@vger.kernel.org

On Thu, Apr 14, 2016 at 10:59:57AM -0400, Eric Chamberland wrote:

> just cloned a repo and it checked-out wihtout any error (with git 2.2.0) but
> got come corrupted files (because I got some sdd failures).
> 
> Then, I get a git core dump when trying to "git status" into the repo which
> have a "bad sector" on sdd drive (crypted partition).
> 
> I tried with git 2.2.0 AND git version 2.8.1.185.gdc0db2c.dirty (just
> modified the Makefile to remove STRIP part)
> 
> In both cases, I have a  Bus error (core dumped)

Interesting. There was a known issue with reading corrupted pack .idx
files, but it was fixed in v2.8.0. So this could be a new thing.

SIGBUS is somewhat rare, though (usually just accessing unmapped memory
should get us a SIGSEGV). What platform are you on? I seem to recall
that hardware like ARM that cares about memory alignment is more likely
to get a SIGBUS.

> Program received signal SIGBUS, Bus error.
> 0x00007ffff7866d58 in ?? () from /lib64/libcrypto.so.1.0.0
> (gdb) bt
> #0  0x00007ffff7866d58 in ?? () from /lib64/libcrypto.so.1.0.0
> #1  0x3334d90d8c20f3f0 in ?? ()
> #2  0xe59b5a6cd844a601 in ?? ()
> #3  0xc587a53f67985ae7 in ?? ()
> #4  0x3ce81893e5541777 in ?? ()
> #5  0xdeb18349a4b042ea in ?? ()
> #6  0x8254de489067ec4b in ?? ()
> #7  0x6fbef2439704c81b in ?? ()
> #8  0xe0eee2bb385a96da in ?? ()
> #9  0x00007ffff6e19ab3 in ?? ()
> #10 0x00007fffffffc4d0 in ?? ()
> #11 0x000000000000001d in ?? ()
> #12 0x00007ffff7863f80 in SHA1_Update () from /lib64/libcrypto.so.1.0.0
> #13 0x00000000005102c0 in write_sha1_file_prepare
> (buf=buf@entry=0x7ffff6c81000, len=1673936, type=<optimized out>,
> sha1=sha1@entry=0x7fffffffc750 "\340_~", hdr=hdr@entry=0x7fffffffc570 "blob
> 1673936",

So I'd assume here that the problem is in accessing the memory in "buf".
to actually compute the sha1. That is mmap'd data, but the process is
fairly bland (mmap however many bytes stat() tells us the file has, and
then compute the sha1). You mentioned a bad sector; could it be that the
filesystem is corrupted, and the OS is giving us SIGBUS when trying to
read unavailable bytes from an mmap'd file?

That would explain the SIGBUS versus SIGSEGV.

What happens if you "cat" the file in question:

> #15 0x00000000005159f8 in index_mem (sha1=sha1@entry=0x7fffffffc750
> "\340_~", buf=buf@entry=0x7ffff6c81000, size=1673936,
> type=type@entry=OBJ_BLOB,
>     path=path@entry=0x80a818 "Ressources/dev/Test.ExportationVTK/Ressources.Avion/Avion.Quadratique.cont.vtu.etalon",
> flags=flags@entry=0) at sha1_file.c:3305

Can it show all of the bytes? I guess from the "size" field it's too big
to manually verify, but "cat >/dev/null" should be enough to see if we
can read the whole thing.

> Ii would have expected git to first gave me an error when checking out the
> files!!! Here is the log:
> 
> Checking out files:  99% (28645/28934)
> Checking out files: 100% (28934/28934)
> Checking out files: 100% (28934/28934), done.
> Already on 'master'
> Your branch is up-to-date with 'origin/master'.
>     On valide le dépôt TestValidation avec la référence:
> 9b4a485202b2b52922377842c15bfd605d240667
> HEAD is now at 9b4a485 BUG: On spécifie bash comme shell...
> 
> But at least 1 file is corrupted!
> 
> I keep preciously this faulty repo to further investigation with someone who
> can help dig into the coredump and correct it...

So _if_ my guess is right that you have filesystem corruption, git may
not even know about it. It wrote the file, and the OS said "OK,
success", not knowing it had been partially corrupted.

And if that guess is right, it also means there's no git bug to fix.
SIGBUS is the natural way for the OS to tell the process that mmap'd
data isn't available.

-Peff

^ permalink raw reply	[relevance 0%]

* Re: 0 bot for Git
  2016-04-13 17:29  4%                 ` Stefan Beller
  2016-04-13 17:43  0%                   ` Greg KH
@ 2016-04-16 15:51  0%                   ` Lars Schneider
  1 sibling, 0 replies; 200+ results
From: Lars Schneider @ 2016-04-16 15:51 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Junio C Hamano, Matthieu Moy, lkp, Greg KH, git@vger.kernel.org


On 13 Apr 2016, at 19:29, Stefan Beller <sbeller@google.com> wrote:

> On Wed, Apr 13, 2016 at 10:09 AM, Lars Schneider
> <larsxschneider@gmail.com> wrote:
>> 
>>> On 13 Apr 2016, at 18:27, Junio C Hamano <gitster@pobox.com> wrote:
>>> 
>>> Lars Schneider <larsxschneider@gmail.com> writes:
>>> 
>>>> @Junio:
>>>> If you setup Travis CI for your https://github.com/gitster/git fork
>>>> then Travis CI would build all your topic branches and you (and
>>>> everyone who is interested) could check
>>>> https://travis-ci.org/gitster/git/branches to see which branches
>>>> will break pu if you integrate them.
>>> 
>>> I would not say such an arrangement is worthless, but it targets a
>>> wrong point in the patch flow.
>>> 
>>> The patches that result in the most wastage of my time (i.e. a
>>> shared bottleneck resource the community should strive to optimize
>>> for) are the ones that fail to hit 'pu'.  Ones that do not even
>>> build in isolation, ones that may build but fail even the new tests
>>> they bring in, ones that break existing tests, and ones that are OK
>>> in isolation but do not play well with topics already in flight.
>> 
>> I am not sure what you mean by "fail to hit 'pu'". Maybe we talk at
>> cross purposes. Here is what I think you do, please correct me:
>> 
>> 1.) You pick the topics from the mailing list and create feature
>>    branches for each one of them. E.g. one of my recent topics
>>    is "ls/config-origin".
> 
> and by You you mean Junio.
Yes.


> Ideally the 0bot would have sent the message as a reply to the
> cover letter with the information "doesn't compile/breaks test t1234",
> so Junio could ignore that series (no time wasted on his part).
> 
> At Git Merge Greg said (paraphrasing here):
> 
>  We waste developers time, because we have plenty of it. Maintainers time
>  however is precious because maintainers are the bottleneck and a scare
>  resource to come by.
> 
> And I think Git and the kernel have the same community design here.
> (Except the kernel is bigger and has more than one maintainer)
> 
> So the idea is help Junio make a decision to drop/ignore those patches
> with least amount of brain cycled spent as possible. (Not even spend 5
> seconds on it).
That sounds great. I just wonder how 0bot would know where to apply
the patches?


>> 2.) At some point you create a new pu branch based on the latest
>>    next branch. You merge all the new topics into the new pu.
> 
> but Junio also runs test after each(?) merge(?) of a series and once
> tests fail, it takes time to sort out, what caused it. (Is that the patch series
> alone or is that because 2 series interact badly with each other?)
> 
>> 
>> If you push the topics to github.com/gitster after step 1 then
>> Travis CI could tell you if the individual topic builds clean
>> and passes all tests. Then you could merge only clean topics in
>> step 2 which would result in a pu that is much more likely to
>> build clean.
> 
> IIRC Junio did not like granting travis access to the "blessed" repository
> as travis wants so much permissions including write permission to that
> repo. (We/He could have a second non advertised repo though)
AFAIK TravisCI does not ask for repo write permissions. They ask for
permission to write the status of commits (little green checkmark on
GitHub) and repo hooks:
https://docs.travis-ci.com/user/github-oauth-scopes


> Also this would incur wait time on Junios side
> 
> 1) collect patches (many series over the day)
> 2) push
> 3) wait
> 4) do the merges
He could do the merges as he does them today but after some time
he (and the contributor of a patch) would know if a certain patch
brakes pu.


> however a 0 bot would do
> 1) collect patches faster than Junio (0 bot is a computer after all,
> working 24/7)
> 2) test each patch/series individually
> 3) send feedback without the wait time, so the contributor from a different
>   time zone gets feedback quickly. (round trip is just the build and test time,
>   which the developer forgot to do any way if it fails)
I agree that this would be even better. However, I assume this mechanism
requires some setup? TravisCI works today.


> 
>> 
>> Could that process avoid wasting your time with bad patches?
>> 
>>> Automated testing of what is already on 'pu' does not help reduce
>>> the above cost, as the culling must be done by me _without_ help
>>> from automated test you propose to run on topics in 'pu'.  Ever
>>> heard of chicken and egg?
>>> 
>>> Your "You can setup your own CI" update to SubmittingPatches may
>>> encourage people to test before sending.  The "Travis CI sends
>>> failure notice as a response to a crappy patch" discussed by
>>> Matthieu in the other subthread will be of great help.
>>> 
>>> Thanks.
>>> 
>> 

^ permalink raw reply	[relevance 0%]

* Re: [PATCH] Move test-* to t/helper/ subdirectory
  2016-04-13 13:22  1% [PATCH] Move test-* to t/helper/ subdirectory Nguyễn Thái Ngọc Duy
@ 2016-04-15 15:09  0% ` Junio C Hamano
    1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2016-04-15 15:09 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> This keeps top dir a bit less crowded. And because these programs are
> for testing purposes, it makes sense that they stay somewhere in t/

But leaves many *.o files after "make clean".  Even "distclean" does
not clean them.

>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  This patch will break any patches that add new test programs.
>  Luckily, none in 'next' or 'pu' does that. I know lmdb backend adds
>  test-lmdb-backend, so a manual move and some .gitignore fixup is
>  required there.
>
>  .gitignore                                         | 33 ----------------------
>  Makefile                                           | 24 ++++++++--------
>  t/helper/.gitignore (new)                          | 33 ++++++++++++++++++++++
>  test-chmtime.c => t/helper/test-chmtime.c          |  0
>  test-config.c => t/helper/test-config.c            |  0
>  test-ctype.c => t/helper/test-ctype.c              |  0
>  test-date.c => t/helper/test-date.c                |  0
>  test-delta.c => t/helper/test-delta.c              |  0
>  .../helper/test-dump-cache-tree.c                  |  0
>  .../helper/test-dump-split-index.c                 |  0
>  .../helper/test-dump-untracked-cache.c             |  0
>  test-fake-ssh.c => t/helper/test-fake-ssh.c        |  0
>  test-genrandom.c => t/helper/test-genrandom.c      |  0
>  test-hashmap.c => t/helper/test-hashmap.c          |  0
>  .../helper/test-index-version.c                    |  0
>  test-line-buffer.c => t/helper/test-line-buffer.c  |  0
>  test-match-trees.c => t/helper/test-match-trees.c  |  0
>  test-mergesort.c => t/helper/test-mergesort.c      |  0
>  test-mktemp.c => t/helper/test-mktemp.c            |  0
>  .../helper/test-parse-options.c                    |  0
>  test-path-utils.c => t/helper/test-path-utils.c    |  0
>  test-prio-queue.c => t/helper/test-prio-queue.c    |  0
>  test-read-cache.c => t/helper/test-read-cache.c    |  0
>  test-regex.c => t/helper/test-regex.c              |  0
>  .../helper/test-revision-walking.c                 |  0
>  test-run-command.c => t/helper/test-run-command.c  |  0
>  .../helper/test-scrap-cache-tree.c                 |  0
>  test-sha1-array.c => t/helper/test-sha1-array.c    |  0
>  test-sha1.c => t/helper/test-sha1.c                |  0
>  test-sha1.sh => t/helper/test-sha1.sh              |  4 +--
>  test-sigchain.c => t/helper/test-sigchain.c        |  0
>  test-string-list.c => t/helper/test-string-list.c  |  0
>  .../helper/test-submodule-config.c                 |  0
>  test-subprocess.c => t/helper/test-subprocess.c    |  0
>  test-svn-fe.c => t/helper/test-svn-fe.c            |  0
>  .../helper/test-urlmatch-normalization.c           |  0
>  test-wildmatch.c => t/helper/test-wildmatch.c      |  0
>  t/t5601-clone.sh                                   |  2 +-
>  t/test-lib.sh                                      |  4 +--
>  39 files changed, 50 insertions(+), 50 deletions(-)
>  create mode 100644 t/helper/.gitignore
>  rename test-chmtime.c => t/helper/test-chmtime.c (100%)
>  rename test-config.c => t/helper/test-config.c (100%)
>  rename test-ctype.c => t/helper/test-ctype.c (100%)
>  rename test-date.c => t/helper/test-date.c (100%)
>  rename test-delta.c => t/helper/test-delta.c (100%)
>  rename test-dump-cache-tree.c => t/helper/test-dump-cache-tree.c (100%)
>  rename test-dump-split-index.c => t/helper/test-dump-split-index.c (100%)
>  rename test-dump-untracked-cache.c => t/helper/test-dump-untracked-cache.c (100%)
>  rename test-fake-ssh.c => t/helper/test-fake-ssh.c (100%)
>  rename test-genrandom.c => t/helper/test-genrandom.c (100%)
>  rename test-hashmap.c => t/helper/test-hashmap.c (100%)
>  rename test-index-version.c => t/helper/test-index-version.c (100%)
>  rename test-line-buffer.c => t/helper/test-line-buffer.c (100%)
>  rename test-match-trees.c => t/helper/test-match-trees.c (100%)
>  rename test-mergesort.c => t/helper/test-mergesort.c (100%)
>  rename test-mktemp.c => t/helper/test-mktemp.c (100%)
>  rename test-parse-options.c => t/helper/test-parse-options.c (100%)
>  rename test-path-utils.c => t/helper/test-path-utils.c (100%)
>  rename test-prio-queue.c => t/helper/test-prio-queue.c (100%)
>  rename test-read-cache.c => t/helper/test-read-cache.c (100%)
>  rename test-regex.c => t/helper/test-regex.c (100%)
>  rename test-revision-walking.c => t/helper/test-revision-walking.c (100%)
>  rename test-run-command.c => t/helper/test-run-command.c (100%)
>  rename test-scrap-cache-tree.c => t/helper/test-scrap-cache-tree.c (100%)
>  rename test-sha1-array.c => t/helper/test-sha1-array.c (100%)
>  rename test-sha1.c => t/helper/test-sha1.c (100%)
>  rename test-sha1.sh => t/helper/test-sha1.sh (96%)
>  rename test-sigchain.c => t/helper/test-sigchain.c (100%)
>  rename test-string-list.c => t/helper/test-string-list.c (100%)
>  rename test-submodule-config.c => t/helper/test-submodule-config.c (100%)
>  rename test-subprocess.c => t/helper/test-subprocess.c (100%)
>  rename test-svn-fe.c => t/helper/test-svn-fe.c (100%)
>  rename test-urlmatch-normalization.c => t/helper/test-urlmatch-normalization.c (100%)
>  rename test-wildmatch.c => t/helper/test-wildmatch.c (100%)
>
> diff --git a/.gitignore b/.gitignore
> index 5087ce1..05cb58a 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -179,39 +179,6 @@
>  /gitweb/gitweb.cgi
>  /gitweb/static/gitweb.js
>  /gitweb/static/gitweb.min.*
> -/test-chmtime
> -/test-ctype
> -/test-config
> -/test-date
> -/test-delta
> -/test-dump-cache-tree
> -/test-dump-split-index
> -/test-dump-untracked-cache
> -/test-fake-ssh
> -/test-scrap-cache-tree
> -/test-genrandom
> -/test-hashmap
> -/test-index-version
> -/test-line-buffer
> -/test-match-trees
> -/test-mergesort
> -/test-mktemp
> -/test-parse-options
> -/test-path-utils
> -/test-prio-queue
> -/test-read-cache
> -/test-regex
> -/test-revision-walking
> -/test-run-command
> -/test-sha1
> -/test-sha1-array
> -/test-sigchain
> -/test-string-list
> -/test-submodule-config
> -/test-subprocess
> -/test-svn-fe
> -/test-urlmatch-normalization
> -/test-wildmatch
>  /common-cmds.h
>  *.tar.gz
>  *.dsc
> diff --git a/Makefile b/Makefile
> index 2742a69..0a5fb9d 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -624,7 +624,7 @@ TEST_PROGRAMS_NEED_X += test-svn-fe
>  TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
>  TEST_PROGRAMS_NEED_X += test-wildmatch
>  
> -TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
> +TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
>  
>  # List built-in command $C whose implementation cmd_$C() is not in
>  # builtin/$C.o but is linked in as part of some other command.
> @@ -1904,7 +1904,7 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
>  VCSSVN_OBJS += vcs-svn/svndiff.o
>  VCSSVN_OBJS += vcs-svn/svndump.o
>  
> -TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
> +TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
>  OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
>  	$(XDIFF_OBJS) \
>  	$(VCSSVN_OBJS) \
> @@ -2211,7 +2211,7 @@ bin-wrappers/%: wrap-for-bin.sh
>  	@mkdir -p bin-wrappers
>  	$(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
>  	     -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
> -	     -e 's|@@PROG@@|$(@F)|' < $< > $@ && \
> +	     -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))|' < $< > $@ && \
>  	chmod +x $@
>  
>  # GNU make supports exporting all variables by "export" without parameters.
> @@ -2231,25 +2231,25 @@ perf: all
>  
>  .PHONY: test perf
>  
> -test-ctype$X: ctype.o
> +t/helper/test-ctype$X: ctype.o
>  
> -test-date$X: date.o ctype.o
> +t/helper/test-date$X: date.o ctype.o
>  
> -test-delta$X: diff-delta.o patch-delta.o
> +t/helper/test-delta$X: diff-delta.o patch-delta.o
>  
> -test-line-buffer$X: vcs-svn/lib.a
> +t/helper/test-line-buffer$X: vcs-svn/lib.a
>  
> -test-parse-options$X: parse-options.o parse-options-cb.o
> +t/helper/test-parse-options$X: parse-options.o parse-options-cb.o
>  
> -test-svn-fe$X: vcs-svn/lib.a
> +t/helper/test-svn-fe$X: vcs-svn/lib.a
>  
>  .PRECIOUS: $(TEST_OBJS)
>  
> -test-%$X: test-%.o GIT-LDFLAGS $(GITLIBS)
> +t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
>  	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
>  
> -check-sha1:: test-sha1$X
> -	./test-sha1.sh
> +check-sha1:: t/helper/test-sha1$X
> +	t/helper/test-sha1.sh
>  
>  SP_OBJ = $(patsubst %.o,%.sp,$(C_OBJ))
>  
> diff --git a/t/helper/.gitignore b/t/helper/.gitignore
> new file mode 100644
> index 0000000..d6e8b36
> --- /dev/null
> +++ b/t/helper/.gitignore
> @@ -0,0 +1,33 @@
> +/test-chmtime
> +/test-ctype
> +/test-config
> +/test-date
> +/test-delta
> +/test-dump-cache-tree
> +/test-dump-split-index
> +/test-dump-untracked-cache
> +/test-fake-ssh
> +/test-scrap-cache-tree
> +/test-genrandom
> +/test-hashmap
> +/test-index-version
> +/test-line-buffer
> +/test-match-trees
> +/test-mergesort
> +/test-mktemp
> +/test-parse-options
> +/test-path-utils
> +/test-prio-queue
> +/test-read-cache
> +/test-regex
> +/test-revision-walking
> +/test-run-command
> +/test-sha1
> +/test-sha1-array
> +/test-sigchain
> +/test-string-list
> +/test-submodule-config
> +/test-subprocess
> +/test-svn-fe
> +/test-urlmatch-normalization
> +/test-wildmatch
> diff --git a/test-chmtime.c b/t/helper/test-chmtime.c
> similarity index 100%
> rename from test-chmtime.c
> rename to t/helper/test-chmtime.c
> diff --git a/test-config.c b/t/helper/test-config.c
> similarity index 100%
> rename from test-config.c
> rename to t/helper/test-config.c
> diff --git a/test-ctype.c b/t/helper/test-ctype.c
> similarity index 100%
> rename from test-ctype.c
> rename to t/helper/test-ctype.c
> diff --git a/test-date.c b/t/helper/test-date.c
> similarity index 100%
> rename from test-date.c
> rename to t/helper/test-date.c
> diff --git a/test-delta.c b/t/helper/test-delta.c
> similarity index 100%
> rename from test-delta.c
> rename to t/helper/test-delta.c
> diff --git a/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
> similarity index 100%
> rename from test-dump-cache-tree.c
> rename to t/helper/test-dump-cache-tree.c
> diff --git a/test-dump-split-index.c b/t/helper/test-dump-split-index.c
> similarity index 100%
> rename from test-dump-split-index.c
> rename to t/helper/test-dump-split-index.c
> diff --git a/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
> similarity index 100%
> rename from test-dump-untracked-cache.c
> rename to t/helper/test-dump-untracked-cache.c
> diff --git a/test-fake-ssh.c b/t/helper/test-fake-ssh.c
> similarity index 100%
> rename from test-fake-ssh.c
> rename to t/helper/test-fake-ssh.c
> diff --git a/test-genrandom.c b/t/helper/test-genrandom.c
> similarity index 100%
> rename from test-genrandom.c
> rename to t/helper/test-genrandom.c
> diff --git a/test-hashmap.c b/t/helper/test-hashmap.c
> similarity index 100%
> rename from test-hashmap.c
> rename to t/helper/test-hashmap.c
> diff --git a/test-index-version.c b/t/helper/test-index-version.c
> similarity index 100%
> rename from test-index-version.c
> rename to t/helper/test-index-version.c
> diff --git a/test-line-buffer.c b/t/helper/test-line-buffer.c
> similarity index 100%
> rename from test-line-buffer.c
> rename to t/helper/test-line-buffer.c
> diff --git a/test-match-trees.c b/t/helper/test-match-trees.c
> similarity index 100%
> rename from test-match-trees.c
> rename to t/helper/test-match-trees.c
> diff --git a/test-mergesort.c b/t/helper/test-mergesort.c
> similarity index 100%
> rename from test-mergesort.c
> rename to t/helper/test-mergesort.c
> diff --git a/test-mktemp.c b/t/helper/test-mktemp.c
> similarity index 100%
> rename from test-mktemp.c
> rename to t/helper/test-mktemp.c
> diff --git a/test-parse-options.c b/t/helper/test-parse-options.c
> similarity index 100%
> rename from test-parse-options.c
> rename to t/helper/test-parse-options.c
> diff --git a/test-path-utils.c b/t/helper/test-path-utils.c
> similarity index 100%
> rename from test-path-utils.c
> rename to t/helper/test-path-utils.c
> diff --git a/test-prio-queue.c b/t/helper/test-prio-queue.c
> similarity index 100%
> rename from test-prio-queue.c
> rename to t/helper/test-prio-queue.c
> diff --git a/test-read-cache.c b/t/helper/test-read-cache.c
> similarity index 100%
> rename from test-read-cache.c
> rename to t/helper/test-read-cache.c
> diff --git a/test-regex.c b/t/helper/test-regex.c
> similarity index 100%
> rename from test-regex.c
> rename to t/helper/test-regex.c
> diff --git a/test-revision-walking.c b/t/helper/test-revision-walking.c
> similarity index 100%
> rename from test-revision-walking.c
> rename to t/helper/test-revision-walking.c
> diff --git a/test-run-command.c b/t/helper/test-run-command.c
> similarity index 100%
> rename from test-run-command.c
> rename to t/helper/test-run-command.c
> diff --git a/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
> similarity index 100%
> rename from test-scrap-cache-tree.c
> rename to t/helper/test-scrap-cache-tree.c
> diff --git a/test-sha1-array.c b/t/helper/test-sha1-array.c
> similarity index 100%
> rename from test-sha1-array.c
> rename to t/helper/test-sha1-array.c
> diff --git a/test-sha1.c b/t/helper/test-sha1.c
> similarity index 100%
> rename from test-sha1.c
> rename to t/helper/test-sha1.c
> diff --git a/test-sha1.sh b/t/helper/test-sha1.sh
> similarity index 96%
> rename from test-sha1.sh
> rename to t/helper/test-sha1.sh
> index cef4bcc..750b95a 100755
> --- a/test-sha1.sh
> +++ b/t/helper/test-sha1.sh
> @@ -1,7 +1,7 @@
>  #!/bin/sh
>  
>  dd if=/dev/zero bs=1048576 count=100 2>/dev/null |
> -/usr/bin/time ./test-sha1 >/dev/null
> +/usr/bin/time t/helper/test-sha1 >/dev/null
>  
>  while read expect cnt pfx
>  do
> @@ -11,7 +11,7 @@ do
>  			test -z "$pfx" || echo "$pfx"
>  			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
>  			perl -pe 'y/\000/g/'
> -		} | ./test-sha1 $cnt
> +		} | ./t/helper/test-sha1 $cnt
>  	)
>  	if test "$expect" = "$actual"
>  	then
> diff --git a/test-sigchain.c b/t/helper/test-sigchain.c
> similarity index 100%
> rename from test-sigchain.c
> rename to t/helper/test-sigchain.c
> diff --git a/test-string-list.c b/t/helper/test-string-list.c
> similarity index 100%
> rename from test-string-list.c
> rename to t/helper/test-string-list.c
> diff --git a/test-submodule-config.c b/t/helper/test-submodule-config.c
> similarity index 100%
> rename from test-submodule-config.c
> rename to t/helper/test-submodule-config.c
> diff --git a/test-subprocess.c b/t/helper/test-subprocess.c
> similarity index 100%
> rename from test-subprocess.c
> rename to t/helper/test-subprocess.c
> diff --git a/test-svn-fe.c b/t/helper/test-svn-fe.c
> similarity index 100%
> rename from test-svn-fe.c
> rename to t/helper/test-svn-fe.c
> diff --git a/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c
> similarity index 100%
> rename from test-urlmatch-normalization.c
> rename to t/helper/test-urlmatch-normalization.c
> diff --git a/test-wildmatch.c b/t/helper/test-wildmatch.c
> similarity index 100%
> rename from test-wildmatch.c
> rename to t/helper/test-wildmatch.c
> diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
> index c1efb8e..150aeaf 100755
> --- a/t/t5601-clone.sh
> +++ b/t/t5601-clone.sh
> @@ -308,7 +308,7 @@ test_expect_success 'clone checking out a tag' '
>  
>  setup_ssh_wrapper () {
>  	test_expect_success 'setup ssh wrapper' '
> -		cp "$GIT_BUILD_DIR/test-fake-ssh$X" \
> +		cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \
>  			"$TRASH_DIRECTORY/ssh-wrapper$X" &&
>  		GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" &&
>  		export GIT_SSH &&
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index 0b47eb6..cd0ecd4 100644
> --- a/t/test-lib.sh
> +++ b/t/test-lib.sh
> @@ -854,10 +854,10 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
>  	error "You haven't built things yet, have you?"
>  }
>  
> -if ! test -x "$GIT_BUILD_DIR"/test-chmtime
> +if ! test -x "$GIT_BUILD_DIR"/t/helper/test-chmtime
>  then
>  	echo >&2 'You need to build test-chmtime:'
> -	echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
> +	echo >&2 'Run "make t/helper/test-chmtime" in the source (toplevel) directory'
>  	exit 1
>  fi

^ permalink raw reply	[relevance 0%]

* git status core dump with bad sector!
@ 2016-04-14 14:59  3% Eric Chamberland
  2016-04-22  5:11  0% ` Jeff King
  0 siblings, 1 reply; 200+ results
From: Eric Chamberland @ 2016-04-14 14:59 UTC (permalink / raw)
  To: git@vger.kernel.org

Hi,

just cloned a repo and it checked-out wihtout any error (with git 2.2.0) 
but got come corrupted files (because I got some sdd failures).

Then, I get a git core dump when trying to "git status" into the repo 
which have a "bad sector" on sdd drive (crypted partition).

I tried with git 2.2.0 AND git version 2.8.1.185.gdc0db2c.dirty (just 
modified the Makefile to remove STRIP part)

In both cases, I have a  Bus error (core dumped)

Tried to make it more verbose:

GIT_TRACE=2 GIT_CURL_VERBOSE=2 GIT_TRACE_PERFORMANCE=2 
GIT_TRACE_PACK_ACCESS=2 GIT_TRACE_PACKET=2 GIT_TRACE_PACKFILE=2 
GIT_TRACE_SETUP=2 GIT_TRACE_SHALLOW=2 /opt/gitgit/bin/git status
10:54:30.644999 trace.c:318             setup: git_dir: .git
10:54:30.645094 trace.c:319             setup: git_common_dir: .git
10:54:30.645102 trace.c:320             setup: worktree: 
/pmi/cmpbib/compilation_BIB_gcc-4.5.1_64bit/TestValidation_avec_erreur_disque_git_core_dump_dans_dev_Test.ExportationVTK_Avion
10:54:30.645112 trace.c:321             setup: cwd: 
/pmi/cmpbib/compilation_BIB_gcc-4.5.1_64bit/TestValidation_avec_erreur_disque_git_core_dump_dans_dev_Test.ExportationVTK_Avion
10:54:30.645151 trace.c:322             setup: prefix: 
Ressources/dev/Test.ExportationVTK/
10:54:30.645181 git.c:350               trace: built-in: git 'status'
Bus error (core dumped)

started in gdb:

Program received signal SIGBUS, Bus error.
0x00007ffff7866d58 in ?? () from /lib64/libcrypto.so.1.0.0
(gdb) bt
#0  0x00007ffff7866d58 in ?? () from /lib64/libcrypto.so.1.0.0
#1  0x3334d90d8c20f3f0 in ?? ()
#2  0xe59b5a6cd844a601 in ?? ()
#3  0xc587a53f67985ae7 in ?? ()
#4  0x3ce81893e5541777 in ?? ()
#5  0xdeb18349a4b042ea in ?? ()
#6  0x8254de489067ec4b in ?? ()
#7  0x6fbef2439704c81b in ?? ()
#8  0xe0eee2bb385a96da in ?? ()
#9  0x00007ffff6e19ab3 in ?? ()
#10 0x00007fffffffc4d0 in ?? ()
#11 0x000000000000001d in ?? ()
#12 0x00007ffff7863f80 in SHA1_Update () from /lib64/libcrypto.so.1.0.0
#13 0x00000000005102c0 in write_sha1_file_prepare 
(buf=buf@entry=0x7ffff6c81000, len=1673936, type=<optimized out>, 
sha1=sha1@entry=0x7fffffffc750 "\340_~", hdr=hdr@entry=0x7fffffffc570 
"blob 1673936",
     hdrlen=hdrlen@entry=0x7fffffffc56c) at sha1_file.c:2951
#14 0x000000000051567b in hash_sha1_file (buf=buf@entry=0x7ffff6c81000, 
len=<optimized out>, type=<optimized out>, 
sha1=sha1@entry=0x7fffffffc750 "\340_~") at sha1_file.c:3010
#15 0x00000000005159f8 in index_mem (sha1=sha1@entry=0x7fffffffc750 
"\340_~", buf=buf@entry=0x7ffff6c81000, size=1673936, 
type=type@entry=OBJ_BLOB,
     path=path@entry=0x80a818 
"Ressources/dev/Test.ExportationVTK/Ressources.Avion/Avion.Quadratique.cont.vtu.etalon", 
flags=flags@entry=0) at sha1_file.c:3305
#16 0x00000000005160ee in index_core (flags=0, path=0x80a818 
"Ressources/dev/Test.ExportationVTK/Ressources.Avion/Avion.Quadratique.cont.vtu.etalon", 
type=OBJ_BLOB, size=<optimized out>, fd=7,
     sha1=0x7fffffffc750 "\340_~") at sha1_file.c:3367
#17 index_fd (sha1=sha1@entry=0x7fffffffc750 "\340_~", fd=7, 
st=st@entry=0x7fffffffc7c0, type=type@entry=OBJ_BLOB,
     path=path@entry=0x80a818 
"Ressources/dev/Test.ExportationVTK/Ressources.Avion/Avion.Quadratique.cont.vtu.etalon", 
flags=flags@entry=0) at sha1_file.c:3410
#18 0x00000000004eac66 in ce_compare_data (st=0x7fffffffc7c0, 
ce=0x80a7c0) at read-cache.c:166
#19 ce_modified_check_fs (ce=0x80a7c0, st=0x7fffffffc7c0) at 
read-cache.c:215
#20 0x00000000004ebb6d in ie_modified (istate=istate@entry=0x7e5fe0 
<the_index>, ce=ce@entry=0x80a7c0, st=st@entry=0x7fffffffc7c0, 
options=options@entry=16) at read-cache.c:395
#21 0x00000000004ebcfe in refresh_cache_ent 
(istate=istate@entry=0x7e5fe0 <the_index>, ce=ce@entry=0x80a7c0, 
options=options@entry=16, err=err@entry=0x7fffffffc908,
     changed_ret=changed_ret@entry=0x7fffffffc90c) at read-cache.c:1130
#22 0x00000000004ed59c in refresh_index (istate=0x7e5fe0 <the_index>, 
flags=flags@entry=6, pathspec=pathspec@entry=0x7bb738 <s.25876+24>, 
seen=seen@entry=0x0, header_msg=header_msg@entry=0x0)
     at read-cache.c:1221
#23 0x0000000000429e3b in cmd_status (argc=<optimized out>, 
argv=0x7fffffffcca0, prefix=0x7e950f 
"Ressources/dev/Test.ExportationVTK/") at builtin/commit.c:1376
#24 0x00000000004063b3 in run_builtin (argv=0x7fffffffcca0, argc=1, 
p=0x7b4030 <commands+2352>) at git.c:352
#25 handle_builtin (argc=1, argv=0x7fffffffcca0) at git.c:539
#26 0x00000000004054a1 in run_argv (argv=0x7fffffffca80, 
argcp=0x7fffffffca6c) at git.c:593
#27 main (argc=1, av=<optimized out>) at git.c:698

Ii would have expected git to first gave me an error when checking out 
the files!!! Here is the log:

Checking out files:  99% (28645/28934)
Checking out files: 100% (28934/28934)
Checking out files: 100% (28934/28934), done.
Already on 'master'
Your branch is up-to-date with 'origin/master'.
     On valide le dépôt TestValidation avec la référence: 
9b4a485202b2b52922377842c15bfd605d240667
HEAD is now at 9b4a485 BUG: On spécifie bash comme shell...

But at least 1 file is corrupted!

I keep preciously this faulty repo to further investigation with someone 
who can help dig into the coredump and correct it...

I am available to recompile a new git to help...

Thanks,

Eric

^ permalink raw reply	[relevance 3%]

* Re: 0 bot for Git
  2016-04-13 17:29  4%                 ` Stefan Beller
@ 2016-04-13 17:43  0%                   ` Greg KH
  2016-04-16 15:51  0%                   ` Lars Schneider
  1 sibling, 0 replies; 200+ results
From: Greg KH @ 2016-04-13 17:43 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Lars Schneider, Junio C Hamano, Matthieu Moy, lkp,
	git@vger.kernel.org

On Wed, Apr 13, 2016 at 10:29:57AM -0700, Stefan Beller wrote:
> 
> At Git Merge Greg said (paraphrasing here):
> 
>   We waste developers time, because we have plenty of it. Maintainers time
>   however is precious because maintainers are the bottleneck and a scare
>   resource to come by.

s/scare/scarce/

Although some people might disagree :)

^ permalink raw reply	[relevance 0%]

* Re: 0 bot for Git
  @ 2016-04-13 17:29  4%                 ` Stefan Beller
  2016-04-13 17:43  0%                   ` Greg KH
  2016-04-16 15:51  0%                   ` Lars Schneider
  0 siblings, 2 replies; 200+ results
From: Stefan Beller @ 2016-04-13 17:29 UTC (permalink / raw)
  To: Lars Schneider
  Cc: Junio C Hamano, Matthieu Moy, lkp, Greg KH, git@vger.kernel.org

On Wed, Apr 13, 2016 at 10:09 AM, Lars Schneider
<larsxschneider@gmail.com> wrote:
>
>> On 13 Apr 2016, at 18:27, Junio C Hamano <gitster@pobox.com> wrote:
>>
>> Lars Schneider <larsxschneider@gmail.com> writes:
>>
>>> @Junio:
>>> If you setup Travis CI for your https://github.com/gitster/git fork
>>> then Travis CI would build all your topic branches and you (and
>>> everyone who is interested) could check
>>> https://travis-ci.org/gitster/git/branches to see which branches
>>> will break pu if you integrate them.
>>
>> I would not say such an arrangement is worthless, but it targets a
>> wrong point in the patch flow.
>>
>> The patches that result in the most wastage of my time (i.e. a
>> shared bottleneck resource the community should strive to optimize
>> for) are the ones that fail to hit 'pu'.  Ones that do not even
>> build in isolation, ones that may build but fail even the new tests
>> they bring in, ones that break existing tests, and ones that are OK
>> in isolation but do not play well with topics already in flight.
>
> I am not sure what you mean by "fail to hit 'pu'". Maybe we talk at
> cross purposes. Here is what I think you do, please correct me:
>
> 1.) You pick the topics from the mailing list and create feature
>     branches for each one of them. E.g. one of my recent topics
>     is "ls/config-origin".

and by You you mean Junio.

Ideally the 0bot would have sent the message as a reply to the
cover letter with the information "doesn't compile/breaks test t1234",
so Junio could ignore that series (no time wasted on his part).

At Git Merge Greg said (paraphrasing here):

  We waste developers time, because we have plenty of it. Maintainers time
  however is precious because maintainers are the bottleneck and a scare
  resource to come by.

And I think Git and the kernel have the same community design here.
(Except the kernel is bigger and has more than one maintainer)

So the idea is help Junio make a decision to drop/ignore those patches
with least amount of brain cycled spent as possible. (Not even spend 5
seconds on it).

>
> 2.) At some point you create a new pu branch based on the latest
>     next branch. You merge all the new topics into the new pu.

but Junio also runs test after each(?) merge(?) of a series and once
tests fail, it takes time to sort out, what caused it. (Is that the patch series
alone or is that because 2 series interact badly with each other?)

>
> If you push the topics to github.com/gitster after step 1 then
> Travis CI could tell you if the individual topic builds clean
> and passes all tests. Then you could merge only clean topics in
> step 2 which would result in a pu that is much more likely to
> build clean.

IIRC Junio did not like granting travis access to the "blessed" repository
as travis wants so much permissions including write permission to that
repo. (We/He could have a second non advertised repo though)

Also this would incur wait time on Junios side

1) collect patches (many series over the day)
2) push
3) wait
4) do the merges

however a 0 bot would do
1) collect patches faster than Junio (0 bot is a computer after all,
working 24/7)
2) test each patch/series individually
3) send feedback without the wait time, so the contributor from a different
   time zone gets feedback quickly. (round trip is just the build and test time,
   which the developer forgot to do any way if it fails)

>
> Could that process avoid wasting your time with bad patches?
>
>> Automated testing of what is already on 'pu' does not help reduce
>> the above cost, as the culling must be done by me _without_ help
>> from automated test you propose to run on topics in 'pu'.  Ever
>> heard of chicken and egg?
>>
>> Your "You can setup your own CI" update to SubmittingPatches may
>> encourage people to test before sending.  The "Travis CI sends
>> failure notice as a response to a crappy patch" discussed by
>> Matthieu in the other subthread will be of great help.
>>
>> Thanks.
>>
>

^ permalink raw reply	[relevance 4%]

* [PATCH] Move test-* to t/helper/ subdirectory
@ 2016-04-13 13:22  1% Nguyễn Thái Ngọc Duy
  2016-04-15 15:09  0% ` Junio C Hamano
    0 siblings, 2 replies; 200+ results
From: Nguyễn Thái Ngọc Duy @ 2016-04-13 13:22 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This keeps top dir a bit less crowded. And because these programs are
for testing purposes, it makes sense that they stay somewhere in t/

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 This patch will break any patches that add new test programs.
 Luckily, none in 'next' or 'pu' does that. I know lmdb backend adds
 test-lmdb-backend, so a manual move and some .gitignore fixup is
 required there.

 .gitignore                                         | 33 ----------------------
 Makefile                                           | 24 ++++++++--------
 t/helper/.gitignore (new)                          | 33 ++++++++++++++++++++++
 test-chmtime.c => t/helper/test-chmtime.c          |  0
 test-config.c => t/helper/test-config.c            |  0
 test-ctype.c => t/helper/test-ctype.c              |  0
 test-date.c => t/helper/test-date.c                |  0
 test-delta.c => t/helper/test-delta.c              |  0
 .../helper/test-dump-cache-tree.c                  |  0
 .../helper/test-dump-split-index.c                 |  0
 .../helper/test-dump-untracked-cache.c             |  0
 test-fake-ssh.c => t/helper/test-fake-ssh.c        |  0
 test-genrandom.c => t/helper/test-genrandom.c      |  0
 test-hashmap.c => t/helper/test-hashmap.c          |  0
 .../helper/test-index-version.c                    |  0
 test-line-buffer.c => t/helper/test-line-buffer.c  |  0
 test-match-trees.c => t/helper/test-match-trees.c  |  0
 test-mergesort.c => t/helper/test-mergesort.c      |  0
 test-mktemp.c => t/helper/test-mktemp.c            |  0
 .../helper/test-parse-options.c                    |  0
 test-path-utils.c => t/helper/test-path-utils.c    |  0
 test-prio-queue.c => t/helper/test-prio-queue.c    |  0
 test-read-cache.c => t/helper/test-read-cache.c    |  0
 test-regex.c => t/helper/test-regex.c              |  0
 .../helper/test-revision-walking.c                 |  0
 test-run-command.c => t/helper/test-run-command.c  |  0
 .../helper/test-scrap-cache-tree.c                 |  0
 test-sha1-array.c => t/helper/test-sha1-array.c    |  0
 test-sha1.c => t/helper/test-sha1.c                |  0
 test-sha1.sh => t/helper/test-sha1.sh              |  4 +--
 test-sigchain.c => t/helper/test-sigchain.c        |  0
 test-string-list.c => t/helper/test-string-list.c  |  0
 .../helper/test-submodule-config.c                 |  0
 test-subprocess.c => t/helper/test-subprocess.c    |  0
 test-svn-fe.c => t/helper/test-svn-fe.c            |  0
 .../helper/test-urlmatch-normalization.c           |  0
 test-wildmatch.c => t/helper/test-wildmatch.c      |  0
 t/t5601-clone.sh                                   |  2 +-
 t/test-lib.sh                                      |  4 +--
 39 files changed, 50 insertions(+), 50 deletions(-)
 create mode 100644 t/helper/.gitignore
 rename test-chmtime.c => t/helper/test-chmtime.c (100%)
 rename test-config.c => t/helper/test-config.c (100%)
 rename test-ctype.c => t/helper/test-ctype.c (100%)
 rename test-date.c => t/helper/test-date.c (100%)
 rename test-delta.c => t/helper/test-delta.c (100%)
 rename test-dump-cache-tree.c => t/helper/test-dump-cache-tree.c (100%)
 rename test-dump-split-index.c => t/helper/test-dump-split-index.c (100%)
 rename test-dump-untracked-cache.c => t/helper/test-dump-untracked-cache.c (100%)
 rename test-fake-ssh.c => t/helper/test-fake-ssh.c (100%)
 rename test-genrandom.c => t/helper/test-genrandom.c (100%)
 rename test-hashmap.c => t/helper/test-hashmap.c (100%)
 rename test-index-version.c => t/helper/test-index-version.c (100%)
 rename test-line-buffer.c => t/helper/test-line-buffer.c (100%)
 rename test-match-trees.c => t/helper/test-match-trees.c (100%)
 rename test-mergesort.c => t/helper/test-mergesort.c (100%)
 rename test-mktemp.c => t/helper/test-mktemp.c (100%)
 rename test-parse-options.c => t/helper/test-parse-options.c (100%)
 rename test-path-utils.c => t/helper/test-path-utils.c (100%)
 rename test-prio-queue.c => t/helper/test-prio-queue.c (100%)
 rename test-read-cache.c => t/helper/test-read-cache.c (100%)
 rename test-regex.c => t/helper/test-regex.c (100%)
 rename test-revision-walking.c => t/helper/test-revision-walking.c (100%)
 rename test-run-command.c => t/helper/test-run-command.c (100%)
 rename test-scrap-cache-tree.c => t/helper/test-scrap-cache-tree.c (100%)
 rename test-sha1-array.c => t/helper/test-sha1-array.c (100%)
 rename test-sha1.c => t/helper/test-sha1.c (100%)
 rename test-sha1.sh => t/helper/test-sha1.sh (96%)
 rename test-sigchain.c => t/helper/test-sigchain.c (100%)
 rename test-string-list.c => t/helper/test-string-list.c (100%)
 rename test-submodule-config.c => t/helper/test-submodule-config.c (100%)
 rename test-subprocess.c => t/helper/test-subprocess.c (100%)
 rename test-svn-fe.c => t/helper/test-svn-fe.c (100%)
 rename test-urlmatch-normalization.c => t/helper/test-urlmatch-normalization.c (100%)
 rename test-wildmatch.c => t/helper/test-wildmatch.c (100%)

diff --git a/.gitignore b/.gitignore
index 5087ce1..05cb58a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,39 +179,6 @@
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
 /gitweb/static/gitweb.min.*
-/test-chmtime
-/test-ctype
-/test-config
-/test-date
-/test-delta
-/test-dump-cache-tree
-/test-dump-split-index
-/test-dump-untracked-cache
-/test-fake-ssh
-/test-scrap-cache-tree
-/test-genrandom
-/test-hashmap
-/test-index-version
-/test-line-buffer
-/test-match-trees
-/test-mergesort
-/test-mktemp
-/test-parse-options
-/test-path-utils
-/test-prio-queue
-/test-read-cache
-/test-regex
-/test-revision-walking
-/test-run-command
-/test-sha1
-/test-sha1-array
-/test-sigchain
-/test-string-list
-/test-submodule-config
-/test-subprocess
-/test-svn-fe
-/test-urlmatch-normalization
-/test-wildmatch
 /common-cmds.h
 *.tar.gz
 *.dsc
diff --git a/Makefile b/Makefile
index 2742a69..0a5fb9d 100644
--- a/Makefile
+++ b/Makefile
@@ -624,7 +624,7 @@ TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
 TEST_PROGRAMS_NEED_X += test-wildmatch
 
-TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
+TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
 
 # List built-in command $C whose implementation cmd_$C() is not in
 # builtin/$C.o but is linked in as part of some other command.
@@ -1904,7 +1904,7 @@ VCSSVN_OBJS += vcs-svn/fast_export.o
 VCSSVN_OBJS += vcs-svn/svndiff.o
 VCSSVN_OBJS += vcs-svn/svndump.o
 
-TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
+TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
 OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
 	$(XDIFF_OBJS) \
 	$(VCSSVN_OBJS) \
@@ -2211,7 +2211,7 @@ bin-wrappers/%: wrap-for-bin.sh
 	@mkdir -p bin-wrappers
 	$(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
 	     -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
-	     -e 's|@@PROG@@|$(@F)|' < $< > $@ && \
+	     -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))|' < $< > $@ && \
 	chmod +x $@
 
 # GNU make supports exporting all variables by "export" without parameters.
@@ -2231,25 +2231,25 @@ perf: all
 
 .PHONY: test perf
 
-test-ctype$X: ctype.o
+t/helper/test-ctype$X: ctype.o
 
-test-date$X: date.o ctype.o
+t/helper/test-date$X: date.o ctype.o
 
-test-delta$X: diff-delta.o patch-delta.o
+t/helper/test-delta$X: diff-delta.o patch-delta.o
 
-test-line-buffer$X: vcs-svn/lib.a
+t/helper/test-line-buffer$X: vcs-svn/lib.a
 
-test-parse-options$X: parse-options.o parse-options-cb.o
+t/helper/test-parse-options$X: parse-options.o parse-options-cb.o
 
-test-svn-fe$X: vcs-svn/lib.a
+t/helper/test-svn-fe$X: vcs-svn/lib.a
 
 .PRECIOUS: $(TEST_OBJS)
 
-test-%$X: test-%.o GIT-LDFLAGS $(GITLIBS)
+t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
 
-check-sha1:: test-sha1$X
-	./test-sha1.sh
+check-sha1:: t/helper/test-sha1$X
+	t/helper/test-sha1.sh
 
 SP_OBJ = $(patsubst %.o,%.sp,$(C_OBJ))
 
diff --git a/t/helper/.gitignore b/t/helper/.gitignore
new file mode 100644
index 0000000..d6e8b36
--- /dev/null
+++ b/t/helper/.gitignore
@@ -0,0 +1,33 @@
+/test-chmtime
+/test-ctype
+/test-config
+/test-date
+/test-delta
+/test-dump-cache-tree
+/test-dump-split-index
+/test-dump-untracked-cache
+/test-fake-ssh
+/test-scrap-cache-tree
+/test-genrandom
+/test-hashmap
+/test-index-version
+/test-line-buffer
+/test-match-trees
+/test-mergesort
+/test-mktemp
+/test-parse-options
+/test-path-utils
+/test-prio-queue
+/test-read-cache
+/test-regex
+/test-revision-walking
+/test-run-command
+/test-sha1
+/test-sha1-array
+/test-sigchain
+/test-string-list
+/test-submodule-config
+/test-subprocess
+/test-svn-fe
+/test-urlmatch-normalization
+/test-wildmatch
diff --git a/test-chmtime.c b/t/helper/test-chmtime.c
similarity index 100%
rename from test-chmtime.c
rename to t/helper/test-chmtime.c
diff --git a/test-config.c b/t/helper/test-config.c
similarity index 100%
rename from test-config.c
rename to t/helper/test-config.c
diff --git a/test-ctype.c b/t/helper/test-ctype.c
similarity index 100%
rename from test-ctype.c
rename to t/helper/test-ctype.c
diff --git a/test-date.c b/t/helper/test-date.c
similarity index 100%
rename from test-date.c
rename to t/helper/test-date.c
diff --git a/test-delta.c b/t/helper/test-delta.c
similarity index 100%
rename from test-delta.c
rename to t/helper/test-delta.c
diff --git a/test-dump-cache-tree.c b/t/helper/test-dump-cache-tree.c
similarity index 100%
rename from test-dump-cache-tree.c
rename to t/helper/test-dump-cache-tree.c
diff --git a/test-dump-split-index.c b/t/helper/test-dump-split-index.c
similarity index 100%
rename from test-dump-split-index.c
rename to t/helper/test-dump-split-index.c
diff --git a/test-dump-untracked-cache.c b/t/helper/test-dump-untracked-cache.c
similarity index 100%
rename from test-dump-untracked-cache.c
rename to t/helper/test-dump-untracked-cache.c
diff --git a/test-fake-ssh.c b/t/helper/test-fake-ssh.c
similarity index 100%
rename from test-fake-ssh.c
rename to t/helper/test-fake-ssh.c
diff --git a/test-genrandom.c b/t/helper/test-genrandom.c
similarity index 100%
rename from test-genrandom.c
rename to t/helper/test-genrandom.c
diff --git a/test-hashmap.c b/t/helper/test-hashmap.c
similarity index 100%
rename from test-hashmap.c
rename to t/helper/test-hashmap.c
diff --git a/test-index-version.c b/t/helper/test-index-version.c
similarity index 100%
rename from test-index-version.c
rename to t/helper/test-index-version.c
diff --git a/test-line-buffer.c b/t/helper/test-line-buffer.c
similarity index 100%
rename from test-line-buffer.c
rename to t/helper/test-line-buffer.c
diff --git a/test-match-trees.c b/t/helper/test-match-trees.c
similarity index 100%
rename from test-match-trees.c
rename to t/helper/test-match-trees.c
diff --git a/test-mergesort.c b/t/helper/test-mergesort.c
similarity index 100%
rename from test-mergesort.c
rename to t/helper/test-mergesort.c
diff --git a/test-mktemp.c b/t/helper/test-mktemp.c
similarity index 100%
rename from test-mktemp.c
rename to t/helper/test-mktemp.c
diff --git a/test-parse-options.c b/t/helper/test-parse-options.c
similarity index 100%
rename from test-parse-options.c
rename to t/helper/test-parse-options.c
diff --git a/test-path-utils.c b/t/helper/test-path-utils.c
similarity index 100%
rename from test-path-utils.c
rename to t/helper/test-path-utils.c
diff --git a/test-prio-queue.c b/t/helper/test-prio-queue.c
similarity index 100%
rename from test-prio-queue.c
rename to t/helper/test-prio-queue.c
diff --git a/test-read-cache.c b/t/helper/test-read-cache.c
similarity index 100%
rename from test-read-cache.c
rename to t/helper/test-read-cache.c
diff --git a/test-regex.c b/t/helper/test-regex.c
similarity index 100%
rename from test-regex.c
rename to t/helper/test-regex.c
diff --git a/test-revision-walking.c b/t/helper/test-revision-walking.c
similarity index 100%
rename from test-revision-walking.c
rename to t/helper/test-revision-walking.c
diff --git a/test-run-command.c b/t/helper/test-run-command.c
similarity index 100%
rename from test-run-command.c
rename to t/helper/test-run-command.c
diff --git a/test-scrap-cache-tree.c b/t/helper/test-scrap-cache-tree.c
similarity index 100%
rename from test-scrap-cache-tree.c
rename to t/helper/test-scrap-cache-tree.c
diff --git a/test-sha1-array.c b/t/helper/test-sha1-array.c
similarity index 100%
rename from test-sha1-array.c
rename to t/helper/test-sha1-array.c
diff --git a/test-sha1.c b/t/helper/test-sha1.c
similarity index 100%
rename from test-sha1.c
rename to t/helper/test-sha1.c
diff --git a/test-sha1.sh b/t/helper/test-sha1.sh
similarity index 96%
rename from test-sha1.sh
rename to t/helper/test-sha1.sh
index cef4bcc..750b95a 100755
--- a/test-sha1.sh
+++ b/t/helper/test-sha1.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 dd if=/dev/zero bs=1048576 count=100 2>/dev/null |
-/usr/bin/time ./test-sha1 >/dev/null
+/usr/bin/time t/helper/test-sha1 >/dev/null
 
 while read expect cnt pfx
 do
@@ -11,7 +11,7 @@ do
 			test -z "$pfx" || echo "$pfx"
 			dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null |
 			perl -pe 'y/\000/g/'
-		} | ./test-sha1 $cnt
+		} | ./t/helper/test-sha1 $cnt
 	)
 	if test "$expect" = "$actual"
 	then
diff --git a/test-sigchain.c b/t/helper/test-sigchain.c
similarity index 100%
rename from test-sigchain.c
rename to t/helper/test-sigchain.c
diff --git a/test-string-list.c b/t/helper/test-string-list.c
similarity index 100%
rename from test-string-list.c
rename to t/helper/test-string-list.c
diff --git a/test-submodule-config.c b/t/helper/test-submodule-config.c
similarity index 100%
rename from test-submodule-config.c
rename to t/helper/test-submodule-config.c
diff --git a/test-subprocess.c b/t/helper/test-subprocess.c
similarity index 100%
rename from test-subprocess.c
rename to t/helper/test-subprocess.c
diff --git a/test-svn-fe.c b/t/helper/test-svn-fe.c
similarity index 100%
rename from test-svn-fe.c
rename to t/helper/test-svn-fe.c
diff --git a/test-urlmatch-normalization.c b/t/helper/test-urlmatch-normalization.c
similarity index 100%
rename from test-urlmatch-normalization.c
rename to t/helper/test-urlmatch-normalization.c
diff --git a/test-wildmatch.c b/t/helper/test-wildmatch.c
similarity index 100%
rename from test-wildmatch.c
rename to t/helper/test-wildmatch.c
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index c1efb8e..150aeaf 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -308,7 +308,7 @@ test_expect_success 'clone checking out a tag' '
 
 setup_ssh_wrapper () {
 	test_expect_success 'setup ssh wrapper' '
-		cp "$GIT_BUILD_DIR/test-fake-ssh$X" \
+		cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \
 			"$TRASH_DIRECTORY/ssh-wrapper$X" &&
 		GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" &&
 		export GIT_SSH &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 0b47eb6..cd0ecd4 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -854,10 +854,10 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
 	error "You haven't built things yet, have you?"
 }
 
-if ! test -x "$GIT_BUILD_DIR"/test-chmtime
+if ! test -x "$GIT_BUILD_DIR"/t/helper/test-chmtime
 then
 	echo >&2 'You need to build test-chmtime:'
-	echo >&2 'Run "make test-chmtime" in the source (toplevel) directory'
+	echo >&2 'Run "make t/helper/test-chmtime" in the source (toplevel) directory'
 	exit 1
 fi
 
-- 
2.8.0.rc0.210.gd302cd2

^ permalink raw reply related	[relevance 1%]

* [RFC/PATCH 14/18] Add --index-only support for ff_only merges
  @ 2016-04-08  6:58  4% ` Elijah Newren
  0 siblings, 0 replies; 200+ results
From: Elijah Newren @ 2016-04-08  6:58 UTC (permalink / raw)
  To: git; +Cc: Elijah Newren, Elijah Newren

From: Elijah Newren <newren@palantir.com>

Signed-off-by: Elijah Newren <newren@gmail.com>
---
 builtin/merge.c             | 1 +
 builtin/pull.c              | 4 ++--
 cache.h                     | 1 +
 merge.c                     | 4 +++-
 sequencer.c                 | 2 +-
 t/t6043-merge-index-only.sh | 6 +++---
 6 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/builtin/merge.c b/builtin/merge.c
index 5f463ad..b791702 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1443,6 +1443,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 
 		if (checkout_fast_forward(head_commit->object.oid.hash,
 					  commit->object.oid.hash,
+					  index_only,
 					  overwrite_ignore)) {
 			ret = 1;
 			goto done;
diff --git a/builtin/pull.c b/builtin/pull.c
index 10eff03..4f33a89 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -569,7 +569,7 @@ static int pull_into_void(const unsigned char *merge_head,
 	 * index/worktree changes that the user already made on the unborn
 	 * branch.
 	 */
-	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0))
+	if (checkout_fast_forward(EMPTY_TREE_SHA1_BIN, merge_head, 0, 0))
 		return 1;
 
 	if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
@@ -871,7 +871,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"fast-forwarding your working tree from\n"
 			"commit %s."), sha1_to_hex(orig_head));
 
-		if (checkout_fast_forward(orig_head, curr_head, 0))
+		if (checkout_fast_forward(orig_head, curr_head, 0, 0))
 			die(_("Cannot fast-forward your working tree.\n"
 				"After making sure that you saved anything precious from\n"
 				"$ git diff %s\n"
diff --git a/cache.h b/cache.h
index b829410..d51fcbc 100644
--- a/cache.h
+++ b/cache.h
@@ -1785,6 +1785,7 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 		const char *head_arg, struct commit_list *remotes);
 int checkout_fast_forward(const unsigned char *from,
 			  const unsigned char *to,
+			  int index_only,
 			  int overwrite_ignore);
 
 
diff --git a/merge.c b/merge.c
index 5db7d56..a40307c 100644
--- a/merge.c
+++ b/merge.c
@@ -46,6 +46,7 @@ int try_merge_command(const char *strategy, size_t xopts_nr,
 
 int checkout_fast_forward(const unsigned char *head,
 			  const unsigned char *remote,
+			  int index_only,
 			  int overwrite_ignore)
 {
 	struct tree *trees[MAX_UNPACK_TREES];
@@ -72,7 +73,8 @@ int checkout_fast_forward(const unsigned char *head,
 	opts.head_idx = 1;
 	opts.src_index = &the_index;
 	opts.dst_index = &the_index;
-	opts.update = 1;
+	opts.update = !index_only;
+	opts.index_only = index_only;
 	opts.verbose_update = 1;
 	opts.merge = 1;
 	opts.fn = twoway_merge;
diff --git a/sequencer.c b/sequencer.c
index e66f2fe..1b772fb 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -222,7 +222,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
 	struct strbuf err = STRBUF_INIT;
 
 	read_cache();
-	if (checkout_fast_forward(from, to, 1))
+	if (checkout_fast_forward(from, to, 0, 1))
 		exit(128); /* the callee should have complained already */
 
 	strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
diff --git a/t/t6043-merge-index-only.sh b/t/t6043-merge-index-only.sh
index f79782c..cb860f2 100755
--- a/t/t6043-merge-index-only.sh
+++ b/t/t6043-merge-index-only.sh
@@ -224,7 +224,7 @@ test_expect_success 'setup simple merges' '
 	test_tick && git commit -m E
 '
 
-test_expect_failure '--index-only ff update, non-bare' '
+test_expect_success '--index-only ff update, non-bare' '
 	git reset --hard &&
 	git checkout A^0 &&
 
@@ -235,7 +235,7 @@ test_expect_failure '--index-only ff update, non-bare' '
 	test ! -d subdir
 '
 
-test_expect_failure '--index-only ff update, bare' '
+test_expect_success '--index-only ff update, bare' '
 	git clone --bare . bare.clone &&
 	(cd bare.clone &&
 
@@ -250,7 +250,7 @@ test_expect_failure '--index-only ff update, bare' '
 	)
 '
 
-test_expect_failure '--index-only ff update, non-bare with uncommitted changes' '
+test_expect_success '--index-only ff update, non-bare with uncommitted changes' '
 	git clean -fdx &&
 	git reset --hard &&
 	git checkout A^0 &&
-- 
2.8.0.18.gc685494

^ permalink raw reply related	[relevance 4%]

* [PATCH 03/24] t1430: test the output and error of some commands more carefully
  @ 2016-04-07 19:02  6% ` David Turner
  0 siblings, 0 replies; 200+ results
From: David Turner @ 2016-04-07 19:02 UTC (permalink / raw)
  To: git, mhagger

From: Michael Haggerty <mhagger@alum.mit.edu>

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 t/t1430-bad-ref-name.sh | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index c465abe..005e2b1 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -42,7 +42,7 @@ test_expect_success 'git branch shows badly named ref as warning' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch >output 2>error &&
-	grep -e "broken\.\.\.ref" error &&
+	test_i18ngrep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -152,21 +152,25 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '
 	git rev-parse --verify one >expect &&
 	git rev-parse --verify shadow >actual 2>err &&
 	test_cmp expect actual &&
-	test_i18ngrep "ignoring.*refs/tags/shadow" err
+	test_i18ngrep "ignoring dangling symref refs/tags/shadow" err
 '
 
 test_expect_success 'update-ref --no-deref -d can delete reference to broken name' '
 	git symbolic-ref refs/heads/badname refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/badname" &&
 	test_path_is_file .git/refs/heads/badname &&
-	git update-ref --no-deref -d refs/heads/badname &&
-	test_path_is_missing .git/refs/heads/badname
+	git update-ref --no-deref -d refs/heads/badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/badname &&
+	test_must_be_empty output &&
+	test_must_be_empty error
 '
 
 test_expect_success 'update-ref -d can delete broken name' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
-	git update-ref -d refs/heads/broken...ref &&
+	git update-ref -d refs/heads/broken...ref >output 2>error &&
+	test_must_be_empty output &&
+	test_must_be_empty error &&
 	git branch >output 2>error &&
 	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
@@ -175,7 +179,9 @@ test_expect_success 'update-ref -d can delete broken name' '
 test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
 	echo precious >.git/my-private-file &&
 	echo precious >expect &&
-	test_must_fail git update-ref -d my-private-file &&
+	test_must_fail git update-ref -d my-private-file >output 2>error &&
+	test_must_be_empty output &&
+	test_i18ngrep -e "cannot lock .*: unable to resolve reference" error &&
 	test_cmp expect .git/my-private-file
 '
 
-- 
2.4.2.767.g62658d5-twtrsrc

^ permalink raw reply related	[relevance 6%]

* Re: Merge driver not called for locally modified files?
  @ 2016-04-02 16:21  2% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2016-04-02 16:21 UTC (permalink / raw)
  To: Gioele Barabucci; +Cc: git

Gioele Barabucci <gioele@svario.it> writes:

> it seems to me that merge drivers are not called while merging commits
> that touch locally modified (but uncommited) files. Is this correct?

Yes.  "git merge" first notices this situation and stops before it
has to decide which merge driver to use.

When you try to merge commit 'B' when you are at commit 'A', and
have some local changes, and these two branches were forked from a
common ancestor 'X', the history may look like this:

                1
               /
        X--o--A
         \
          --o--B

where '1' is a hypothetical commit that would result if you were to
make a commit with all your local changes, i.e. diff(1,A) is your
uncommitted changes.  As usual, time flows from left to right.

When you merge branch 'B' into your history, you would want to end
up with this history (tentatively ignoring what is in the working
tree):

        X--o--A--M
         \      /
          --o--B

where 'M' is the merge between 'A' and 'B', and the change diff(M,A)
must represent what happened between 'X' and 'B' that did not happen
between 'X' and 'A'.  When A and B are independent and without
conflict, that is roughly the same as diff(B,X), in other words, M
is roughly the same as patch(A,diff(B,X)).

As you haven't committed your local changes, diff(1,A) must not
participate in computing the result M of this merge.  After this
merge is done, the blob in M is checked out to the working tree, but
doing so by overwriting the working tree files would lose your local
changes, and that is the reason why you see this error message:

>     error: Your local changes to the following files would
>     be overwritten by merge:
> 	.local/share/pw/passwords
>     Please, commit your changes or stash them before you can merge.

What you would want at the very end with is like this:

                1  2
               /  /
        X--o--A--M
         \      /
          --o--B

where '2' is a hypothetical commit that would result if you were to
cherry pick '1' on top of 'M', after making 'M' according to
thediscussion above (i.e. ignoring the local changes you made since
'A').  But just like you did not have '1' because you were not ready
to record your changes based on 'A' as a commit, you are not ready
to actually make this commit '2', so you would want your head to be
at 'M' and the state of '2' in your working tree, leaving diff(2,M)
as the local uncommitted change.

However.

"git merge" does not do the "create the hypothetical commit '1'" to
store away the local changes, and it does not do the "cherry pick
'1' to create the hypothetical commit '2'" to forward-port the local
changes on top of the merge result 'M'.

This is primarily because there are two distinct steps in the above
hypothetifcal "enhanced" merge.  Creating 'M' may conflict and you
would have to resolve it, while "git merge" somehow need to remember
it has to further do the "cherry pick of '1'" on the result (but
there is no facility to do so in the system).  And after you resolve
the conflict to help it create the merge result 'M', it has to
somehow remember that it needs to "cherry-pick --no-commit '1'", and
have the user resolve the conflict.  As the presence of '1' is not
made explicit to the user (we do not even create '1'), when the
latter step of patch(M,diff(1,A)) fails in conflicts, it is hard for
the user to attempt to resolve them starting from scratch, which
likely leads to "I lost the local change" when in fact it is more
like "I had some local change, but because the merge result was
vastly different from what I had when I started the local change, I
was unable to forward-port them and instead I had to redo it from
scratch".  It is not a good user experience.

> Is it possible to configure git so that the merge driver is called also
> while merging locally modified files?

No.  But you _can_ do that

                1  2
               /  /
        X--o--A--M
         \      /
          --o--B

thing manually, by following the advice you received from the error
message, by creating '1' yourself.

	$ git merge 78d4f09 ;# should fail

        $ git checkout -b store-local-changes-away
        $ git commit -a -m 'local changes'
        $ git checkout @{-1} ;# come back to the original branch
			      # at this point, "git status" would report
			      # there is no local changes, hence ...

        $ git merge 78d4f09   ;# ...this should succeed

	$ git cherry-pick --no-commit store-local-changes-away

The last step may conflict (this is what I called 'the latter step'
in the explanation) but at least you have the exact state of '1'
recorded and you know what branch (i.e. store-local-changes-away)
contains the changes, so you can resolve the conflicts in your
working tree without fearing "git reset --hard" to clear the slate
in order to start and retry the conflict resolution from scratch
losing your precious local modification.

And after you are done, you can

	$ git branch -D store-local-changes-away

to conclude the whole thing.

You could simplify this somewhat by using "git stash save" before
you run the merge and "git stash pop" after, but because using real
commit and branch to store the local changes away is easier to see
and understand, that is what the error message you saw suggests.

^ permalink raw reply	[relevance 2%]

* [PATCH 01/21] t1430: test the output and error of some commands more carefully
  @ 2016-03-23 10:04  6% ` Michael Haggerty
  2016-03-23 10:04  5% ` [PATCH 05/21] t1430: improve test coverage of deletion of badly-named refs Michael Haggerty
  1 sibling, 0 replies; 200+ results
From: Michael Haggerty @ 2016-03-23 10:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, peff, pclouds, Ramsay Jones, Michael Haggerty

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 t/t1430-bad-ref-name.sh | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index c465abe..005e2b1 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -42,7 +42,7 @@ test_expect_success 'git branch shows badly named ref as warning' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
 	git branch >output 2>error &&
-	grep -e "broken\.\.\.ref" error &&
+	test_i18ngrep -e "ignoring ref with broken name refs/heads/broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
 '
 
@@ -152,21 +152,25 @@ test_expect_success 'rev-parse skips symref pointing to broken name' '
 	git rev-parse --verify one >expect &&
 	git rev-parse --verify shadow >actual 2>err &&
 	test_cmp expect actual &&
-	test_i18ngrep "ignoring.*refs/tags/shadow" err
+	test_i18ngrep "ignoring dangling symref refs/tags/shadow" err
 '
 
 test_expect_success 'update-ref --no-deref -d can delete reference to broken name' '
 	git symbolic-ref refs/heads/badname refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/badname" &&
 	test_path_is_file .git/refs/heads/badname &&
-	git update-ref --no-deref -d refs/heads/badname &&
-	test_path_is_missing .git/refs/heads/badname
+	git update-ref --no-deref -d refs/heads/badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/badname &&
+	test_must_be_empty output &&
+	test_must_be_empty error
 '
 
 test_expect_success 'update-ref -d can delete broken name' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
-	git update-ref -d refs/heads/broken...ref &&
+	git update-ref -d refs/heads/broken...ref >output 2>error &&
+	test_must_be_empty output &&
+	test_must_be_empty error &&
 	git branch >output 2>error &&
 	! grep -e "broken\.\.\.ref" error &&
 	! grep -e "broken\.\.\.ref" output
@@ -175,7 +179,9 @@ test_expect_success 'update-ref -d can delete broken name' '
 test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
 	echo precious >.git/my-private-file &&
 	echo precious >expect &&
-	test_must_fail git update-ref -d my-private-file &&
+	test_must_fail git update-ref -d my-private-file >output 2>error &&
+	test_must_be_empty output &&
+	test_i18ngrep -e "cannot lock .*: unable to resolve reference" error &&
 	test_cmp expect .git/my-private-file
 '
 
-- 
2.8.0.rc3

^ permalink raw reply related	[relevance 6%]

* [PATCH 05/21] t1430: improve test coverage of deletion of badly-named refs
    2016-03-23 10:04  6% ` [PATCH 01/21] t1430: test the output and error of some commands more carefully Michael Haggerty
@ 2016-03-23 10:04  5% ` Michael Haggerty
  1 sibling, 0 replies; 200+ results
From: Michael Haggerty @ 2016-03-23 10:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, peff, pclouds, Ramsay Jones, Michael Haggerty

Check "branch -d broken...ref"

Check various combinations of

* Deleting using "update-ref -d"
* Deleting using "update-ref --no-deref -d"
* Deleting using "branch -d"

in the following combinations of symref -> ref:

* badname -> broken...ref
* badname -> broken...ref (dangling)
* broken...symref -> master
* broken...symref -> idonotexist (dangling)

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 t/t1430-bad-ref-name.sh | 108 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 98 insertions(+), 10 deletions(-)

diff --git a/t/t1430-bad-ref-name.sh b/t/t1430-bad-ref-name.sh
index 612cc32..25ddab4 100755
--- a/t/t1430-bad-ref-name.sh
+++ b/t/t1430-bad-ref-name.sh
@@ -171,16 +171,6 @@ test_expect_success 'for-each-ref emits warnings for broken names' '
 	test_i18ngrep "ignoring ref with broken name refs/heads/broken\.\.\.symref" error
 '
 
-test_expect_success 'update-ref --no-deref -d can delete reference to broken name' '
-	printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
-	test_when_finished "rm -f .git/refs/heads/badname" &&
-	test_path_is_file .git/refs/heads/badname &&
-	git update-ref --no-deref -d refs/heads/badname >output 2>error &&
-	test_path_is_missing .git/refs/heads/badname &&
-	test_must_be_empty output &&
-	test_must_be_empty error
-'
-
 test_expect_success 'update-ref -d can delete broken name' '
 	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
 	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
@@ -192,6 +182,104 @@ test_expect_success 'update-ref -d can delete broken name' '
 	! grep -e "broken\.\.\.ref" output
 '
 
+test_expect_success 'branch -d can delete broken name' '
+	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
+	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
+	git branch -d broken...ref >output 2>error &&
+	test_i18ngrep "Deleted branch broken...ref (was broken)" output &&
+	test_must_be_empty error &&
+	git branch >output 2>error &&
+	! grep -e "broken\.\.\.ref" error &&
+	! grep -e "broken\.\.\.ref" output
+'
+
+test_expect_success 'update-ref --no-deref -d can delete symref to broken name' '
+	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
+	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
+	printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
+	test_when_finished "rm -f .git/refs/heads/badname" &&
+	git update-ref --no-deref -d refs/heads/badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/badname &&
+	test_must_be_empty output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'branch -d can delete symref to broken name' '
+	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
+	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
+	printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
+	test_when_finished "rm -f .git/refs/heads/badname" &&
+	git branch -d badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/badname &&
+	test_i18ngrep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'update-ref --no-deref -d can delete dangling symref to broken name' '
+	printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
+	test_when_finished "rm -f .git/refs/heads/badname" &&
+	git update-ref --no-deref -d refs/heads/badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/badname &&
+	test_must_be_empty output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'branch -d can delete dangling symref to broken name' '
+	printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
+	test_when_finished "rm -f .git/refs/heads/badname" &&
+	git branch -d badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/badname &&
+	test_i18ngrep "Deleted branch badname (was refs/heads/broken\.\.\.ref)" output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'update-ref -d can delete broken name through symref' '
+	cp .git/refs/heads/master .git/refs/heads/broken...ref &&
+	test_when_finished "rm -f .git/refs/heads/broken...ref" &&
+	printf "ref: refs/heads/broken...ref\n" >.git/refs/heads/badname &&
+	test_when_finished "rm -f .git/refs/heads/badname" &&
+	git update-ref -d refs/heads/badname >output 2>error &&
+	test_path_is_missing .git/refs/heads/broken...ref &&
+	test_must_be_empty output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'update-ref --no-deref -d can delete symref with broken name' '
+	printf "ref: refs/heads/master\n" >.git/refs/heads/broken...symref &&
+	test_when_finished "rm -f .git/refs/heads/broken...symref" &&
+	git update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&
+	test_path_is_missing .git/refs/heads/broken...symref &&
+	test_must_be_empty output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'branch -d can delete symref with broken name' '
+	printf "ref: refs/heads/master\n" >.git/refs/heads/broken...symref &&
+	test_when_finished "rm -f .git/refs/heads/broken...symref" &&
+	git branch -d broken...symref >output 2>error &&
+	test_path_is_missing .git/refs/heads/broken...symref &&
+	test_i18ngrep "Deleted branch broken...symref (was refs/heads/master)" output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'update-ref --no-deref -d can delete dangling symref with broken name' '
+	printf "ref: refs/heads/idonotexist\n" >.git/refs/heads/broken...symref &&
+	test_when_finished "rm -f .git/refs/heads/broken...symref" &&
+	git update-ref --no-deref -d refs/heads/broken...symref >output 2>error &&
+	test_path_is_missing .git/refs/heads/broken...symref &&
+	test_must_be_empty output &&
+	test_must_be_empty error
+'
+
+test_expect_success 'branch -d can delete dangling symref with broken name' '
+	printf "ref: refs/heads/idonotexist\n" >.git/refs/heads/broken...symref &&
+	test_when_finished "rm -f .git/refs/heads/broken...symref" &&
+	git branch -d broken...symref >output 2>error &&
+	test_path_is_missing .git/refs/heads/broken...symref &&
+	test_i18ngrep "Deleted branch broken...symref (was refs/heads/idonotexist)" output &&
+	test_must_be_empty error
+'
+
 test_expect_success 'update-ref -d cannot delete non-ref in .git dir' '
 	echo precious >.git/my-private-file &&
 	echo precious >expect &&
-- 
2.8.0.rc3

^ permalink raw reply related	[relevance 5%]

Results 401-600 of ~1300   |  | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2016-03-23 10:04     [PATCH 00/21] replacement for dt/refs-backend-lmdb v7 patch 04/33 Michael Haggerty
2016-03-23 10:04  6% ` [PATCH 01/21] t1430: test the output and error of some commands more carefully Michael Haggerty
2016-03-23 10:04  5% ` [PATCH 05/21] t1430: improve test coverage of deletion of badly-named refs Michael Haggerty
2016-04-02 14:14     Merge driver not called for locally modified files? Gioele Barabucci
2016-04-02 16:21  2% ` Junio C Hamano
2016-04-07 19:02     [PATCH 00/24] Yet another pre-refs-backend series David Turner
2016-04-07 19:02  6% ` [PATCH 03/24] t1430: test the output and error of some commands more carefully David Turner
2016-04-08  6:58     [RFC/PATCH 00/18] Add --index-only option to git merge Elijah Newren
2016-04-08  6:58  4% ` [RFC/PATCH 14/18] Add --index-only support for ff_only merges Elijah Newren
2016-04-13 13:22  1% [PATCH] Move test-* to t/helper/ subdirectory Nguyễn Thái Ngọc Duy
2016-04-15 15:09  0% ` Junio C Hamano
2016-04-26 22:07     ` Junio C Hamano
2016-04-27  0:52       ` Duy Nguyen
2016-04-27 10:18         ` Duy Nguyen
2016-04-27 16:15           ` Junio C Hamano
2016-05-01  0:28  4%         ` Duy Nguyen
     [not found]     <CAGZ79kYWGFN1W0_y72-V6M3n4WLgtLPzs22bWgs1ObCCDt5BfQ@mail.gmail.com>
2016-04-12  4:29     ` 0 bot for Git Stefan Beller
2016-04-12  7:23       ` Matthieu Moy
2016-04-12 14:52         ` Stefan Beller
2016-04-12 20:29           ` Matthieu Moy
2016-04-12 20:49             ` Junio C Hamano
2016-04-13  6:11               ` Lars Schneider
2016-04-13 16:27                 ` Junio C Hamano
2016-04-13 17:09                   ` Lars Schneider
2016-04-13 17:29  4%                 ` Stefan Beller
2016-04-13 17:43  0%                   ` Greg KH
2016-04-16 15:51  0%                   ` Lars Schneider
2016-04-14 14:59  3% git status core dump with bad sector! Eric Chamberland
2016-04-22  5:11  0% ` Jeff King
2016-05-04 20:37  0%   ` Eric Chamberland
2016-04-27 16:57     [PATCH 00/29] Yet more preparation for reference backends Michael Haggerty
2016-04-27 16:57  5% ` [PATCH 24/29] ref_transaction_update(): check refname_is_safe() at a minimum Michael Haggerty
2016-04-27 20:14  0%   ` Junio C Hamano
2016-05-06 16:13     [PATCH v2 00/33] Yet more preparation for reference backends Michael Haggerty
2016-05-06 16:14  5% ` [PATCH v2 28/33] ref_transaction_update(): check refname_is_safe() at a minimum Michael Haggerty
2016-06-12 21:25     Repacking a repository uses up all available disk space Konstantin Ryabitsev
2016-06-12 21:38     ` Jeff King
2016-06-12 21:54       ` Konstantin Ryabitsev
2016-06-12 22:13         ` Jeff King
2016-06-13  0:24  4%       ` Duy Nguyen
2016-06-13  4:58  0%         ` Jeff King
2016-06-13  4:33     [PATCH 0/3] repack --keep-unreachable Jeff King
2016-06-13  4:36  4% ` [PATCH 2/3] repack: add --keep-unreachable option Jeff King
2016-06-14 16:07     'untracked working tree files would be overwritten by merge' on ignored files? Andreas Krey
2016-06-14 17:06  4% ` Junio C Hamano
2016-07-01  7:56  5% [PATCH] Makefile: drop extra dependencies for test helpers Jeff King
2016-07-01  7:59  5% ` [PATCH] Makefile: use VCSSVN_LIB to refer to svn library Jeff King
2016-07-26 16:05     [PATCH v5 00/16] Use merge_recursive() directly in the builtin am Johannes Schindelin
2016-08-01 11:36     ` [PATCH v6 " Johannes Schindelin
2016-08-01 11:44       ` [PATCH v6 06/16] merge_recursive: abort properly upon errors Johannes Schindelin
2016-08-01 18:41         ` Junio C Hamano
2016-08-02  8:12           ` Johannes Schindelin
2016-08-02 21:26             ` Junio C Hamano
2016-08-03 11:59               ` patch submission process, was " Johannes Schindelin
2016-08-03 15:33                 ` Junio C Hamano
2016-08-03 16:07                   ` Johannes Schindelin
2016-08-03 17:47                     ` Stefan Beller
2016-08-04 15:58  3%                   ` Johannes Schindelin
2016-07-31  9:21     [RFC/PATCH v11 01/13] bisect--helper: use OPT_CMDMODE instead of OPT_BOOL Pranit Bauva
2016-07-31  9:21     ` [RFC/PATCH v11 13/13] bisect--helper: `bisect_start` shell function partially in C Pranit Bauva
2016-08-02 20:19  5%   ` Junio C Hamano
2016-08-03 20:49  4%     ` Pranit Bauva
2016-08-15  7:52  4% [PATCH 1/1] do not add common-main to lib Christian Hesse
2016-08-19 18:10     [PATCH v3 1/3] diff-highlight: add some tests Junio C Hamano
2016-08-19 20:18     ` [PATCH] " Brian Henderson
2016-08-19 20:44  4%   ` Junio C Hamano
2016-08-19 21:04  0%     ` Jeff King
2016-09-30 16:14     "Purposes, Concepts,Misfits, and a Redesign of Git" (a research paper) Konstantin Khomoutov
2016-09-30 22:24  1% ` Jakub Narębski
     [not found]       ` <CAKbZu+BUOAjixTmEC4octseyJbMnFuaCTtLT9hx3H10=AECeKw@mail.gmail.com>
2016-10-05 10:14  3%     ` Jakub Narębski
2016-10-05 10:42  0%       ` Duy Nguyen
2016-10-02 16:59  1% [PATCH] l10n: de.po: translate 260 new messages Ralf Thielow
2016-10-07 16:45  1% ` [PATCH v2] " Ralf Thielow
2016-10-11 23:46     [PATCH] convert: mark a file-local symbol static Ramsay Jones
2016-10-15 15:05     ` Lars Schneider
2016-10-15 21:01       ` Ramsay Jones
2016-10-16  0:15         ` Lars Schneider
2016-10-17  1:37           ` Ramsay Jones
2016-10-17  2:18             ` Jeff King
2016-10-17  9:04               ` Johannes Schindelin
2016-10-17  9:37                 ` Jeff King
2016-10-17 17:21                   ` Ramsay Jones
2016-10-17 20:07                     ` Junio C Hamano
2016-10-17 20:48  4%                   ` Stefan Beller
2016-10-19  9:18     Drastic jump in the time required for the test suite Johannes Schindelin
2016-10-19 17:32     ` Junio C Hamano
2016-10-19 20:56       ` Jeff King
2016-10-20 10:50  4%     ` Johannes Schindelin
2016-10-20 11:39  0%       ` Jeff King
2016-11-01 10:28     Git issue Halde, Faiz
2016-11-01 17:45     ` Jeff King
2016-11-01 18:11       ` Junio C Hamano
2016-11-07 22:34  4%     ` Git issue - ignoring changes to tracked file with assume-unchanged Jakub Narębski
2016-11-15 23:06     [RFC PATCH 00/16] Checkout aware of Submodules! Stefan Beller
2016-11-15 23:06     ` [PATCH 11/16] teach unpack_trees() to remove submodule contents Stefan Beller
     [not found]       ` <20161117133538.GF39230@book.hvoigt.net>
2016-11-18 19:25  0%     ` Stefan Beller
2017-02-05 12:57     [PATCH/RFC] WIP: log: allow "-" as a short-hand for "previous branch" Siddharth Kannan
2017-02-06  0:15     ` Junio C Hamano
2017-02-06 18:10       ` Siddharth Kannan
2017-02-06 23:09  4%     ` Junio C Hamano
2017-02-22 21:08     [PATCH] Documentation: Link git-ls-files to core.quotePath variable Andreas Heiduk
2017-02-24 20:37  4% ` [PATCH v2 0/2] " Andreas Heiduk
2017-03-17 20:42     Bug with .gitignore and branch switching Nevada Sanchez
2017-03-17 21:23  6% ` Junio C Hamano
2017-03-17 21:58  0%   ` Stefan Beller
2017-03-17 22:02  0%   ` Jonathan Nieder
2017-03-17 22:36  4%     ` Junio C Hamano
2017-03-18  3:40  6%     ` Duy Nguyen
2017-03-18  4:30  3%   ` Nevada Sanchez
2017-03-17 21:54  5% ` Jonathan Nieder
2017-03-18 21:19     [PATCH 00/20] object_id part 7 brian m. carlson
2017-03-18 21:19  3% ` [PATCH 13/20] builtin/pull: convert to struct object_id brian m. carlson
2017-03-26  3:15     [GSoC] Proposal: turn git-add--interactive.perl into a builtin Daniel Ferreira (theiostream)
2017-03-28 18:05     ` Stefan Beller
2017-03-30  0:01       ` Johannes Schindelin
2017-03-31  5:07  3%     ` Daniel Ferreira (theiostream)
2017-03-31 19:06  0%       ` Daniel Ferreira (theiostream)
2017-03-26 16:01     [PATCH v2 00/21] object_id part 7 brian m. carlson
2017-03-26 16:01  3% ` [PATCH v2 14/21] builtin/pull: convert to struct object_id brian m. carlson
2017-03-31  1:39     [PATCH v3 00/20] object_id part 7 brian m. carlson
2017-03-31  1:39  3% ` [PATCH v3 13/20] builtin/pull: convert to struct object_id brian m. carlson
2017-03-31 16:05     SHA1 collision in production repo?! (probably not) Lars Schneider
2017-03-31 17:35     ` Junio C Hamano
2017-03-31 17:45       ` Jeff King
2017-09-12 16:18         ` Lars Schneider
2017-09-12 17:38  4%       ` Jeff King
2017-04-13 20:27     [PATCH] repack: respect gc.pid lock David Turner
2017-04-14 19:33     ` Jeff King
2017-04-17 23:29       ` David Turner
2017-04-18  3:41         ` Jeff King
2017-04-18 17:08  4%       ` David Turner
2017-04-15 11:36     Git allow to unconditionaly remove files on other developer host KES
2017-04-15 12:27  4% ` Johannes Sixt
2017-04-15 12:53  0%   ` Konstantin Khomoutov
2017-04-23 21:34     [PATCH 00/53] object_id part 8 brian m. carlson
2017-04-23 21:34  6% ` [PATCH 05/53] builtin/prune: convert to struct object_id brian m. carlson
2017-04-23 21:34  4% ` [PATCH 48/53] merge: convert checkout_fast_forward " brian m. carlson
2017-05-01  2:28     [PATCH v2 00/53] object_id part 8 brian m. carlson
2017-05-01  2:28  6% ` [PATCH v2 05/53] builtin/prune: convert to struct object_id brian m. carlson
2017-05-01  2:29  4% ` [PATCH v2 48/53] merge: convert checkout_fast_forward " brian m. carlson
2017-05-06 22:09     [PATCH v3 00/53] object_id part 8 brian m. carlson
2017-05-06 22:09  6% ` [PATCH v3 05/53] builtin/prune: convert to struct object_id brian m. carlson
2017-05-06 22:10  4% ` [PATCH v3 48/53] merge: convert checkout_fast_forward " brian m. carlson
2017-05-27 10:03  9% mergetool: what to do about deleting precious files? Philip Oakley
2017-05-28  1:14  5% ` Junio C Hamano
2017-05-28 10:24  5%   ` Philip Oakley
2017-05-28 13:06  5%     ` Junio C Hamano
2017-05-29 12:57 10%       ` Philip Oakley
2017-05-30  0:52  5%         ` Junio C Hamano
2017-05-30 23:04  5%           ` Philip Oakley
2017-05-31  0:02  5%             ` Junio C Hamano
2017-06-26 17:24     [PATCH/RFC] commit-template: improve readability of commit template Kaartic Sivaraam
2017-06-26 21:59     ` Junio C Hamano
2017-06-27 17:22       ` Kaartic Sivaraam
2017-06-27 17:56  4%     ` Junio C Hamano
2017-06-28 13:04  0%       ` Kaartic Sivaraam
2017-06-28 14:50  0%         ` Kaartic Sivaraam
2017-07-14 16:12  2% [PATCH] l10n: de.po: update German translation Ralf Thielow
2017-07-21 17:01  2% ` [PATCH v3] " Ralf Thielow
2017-07-20 18:36     [PATCH] " Matthias Rüster
2017-07-21 15:11  2% ` [PATCH v2] " Ralf Thielow
2017-07-25 14:34     [PATCH/RFC] contrib: rerere-train overwrites existing resolutions Raman Gupta
2017-07-25 21:18  4% ` Junio C Hamano
2017-07-26 23:29     [RFC PATCH 0/4] Some patches for fsck for missing objects Jonathan Tan
2017-07-26 23:29     ` [RFC PATCH 1/4] environment, fsck: introduce lazyobject extension Jonathan Tan
2017-07-27 18:55       ` Junio C Hamano
2017-07-28 13:20  4%     ` Ben Peart
2017-08-23 20:13  3% Undocumented change in `git branch -M` behavior Nish Aravamudan
2017-08-24  5:32  0% ` Kevin Daudt
2017-11-15 15:08     [RFC] Indicate that Git waits for user input via editor Lars Schneider
2017-11-15 17:51     ` Stefan Beller
2017-11-15 18:07       ` Lars Schneider
2017-11-15 18:37  4%     ` Stefan Beller
2017-11-30  3:16     How hard would it be to implement sparse fetching/pulling? Vitaly Arbuzov
2017-11-30 14:24     ` Jeff Hostetler
2017-11-30 17:01       ` Vitaly Arbuzov
2017-11-30 17:44         ` Vitaly Arbuzov
2017-11-30 23:43           ` Philip Oakley
2017-12-01  1:27             ` Vitaly Arbuzov
2017-12-01  1:51               ` Vitaly Arbuzov
2017-12-01 14:30                 ` Jeff Hostetler
2017-12-02 16:30  3%               ` Philip Oakley
2017-12-04 15:36  0%                 ` Jeff Hostetler
2017-12-05 23:46  0%                   ` Philip Oakley
2017-12-23  6:10  3% Bring together merge and rebase Carl Baldwin
2017-12-23 18:59  0% ` Ævar Arnfjörð Bjarmason
2017-12-23 22:30  0%   ` Johannes Schindelin
2017-12-25  3:52  0% ` Theodore Ts'o
2017-12-27  4:35  0%   ` Carl Baldwin
2017-12-26  4:08  0% ` Mike Hommey
2018-01-21 12:02 21% [PATCH] worktree: teach "add" to check out existing branches Thomas Gummerer
2018-01-22 11:18  0% ` Duy Nguyen
2018-01-22 20:17  0%   ` Thomas Gummerer
2018-02-04 22:13     ` [PATCH v2 0/3] " Thomas Gummerer
2018-02-04 22:13 21%   ` [PATCH v2 3/3] " Thomas Gummerer
2018-03-17 22:08       ` [PATCH v3 0/4] " Thomas Gummerer
2018-03-17 22:08 21%     ` [PATCH v3 4/4] " Thomas Gummerer
2018-03-17 22:22         ` [PATCH v4 0/4] " Thomas Gummerer
2018-03-17 22:22 21%       ` [PATCH v4 4/4] " Thomas Gummerer
2018-03-20  8:02  6%         ` Eric Sunshine
2018-03-24 21:00  0%           ` Thomas Gummerer
2018-03-25 13:49  9%       ` [PATCH v5 0/6] " Thomas Gummerer
2018-03-25 13:49 21%         ` [PATCH v5 5/6] " Thomas Gummerer
2018-03-27  9:04  7%           ` Eric Sunshine
2018-03-30 14:04  0%             ` Thomas Gummerer
2018-03-25 13:49 17%         ` [PATCH v5 6/6] t2025: rename now outdated branch name Thomas Gummerer
2018-03-31 15:17             ` [PATCH v6 0/6] worktree: teach "add" to check out existing branches Thomas Gummerer
2018-03-31 15:18  9%           ` [PATCH v6 6/6] " Thomas Gummerer
2018-04-15 20:29               ` [PATCH v7 0/4] " Thomas Gummerer
2018-04-15 20:29  9%             ` [PATCH v7 4/4] " Thomas Gummerer
2018-04-23 19:38                 ` [PATCH v8 0/4] " Thomas Gummerer
2018-04-23 19:38  9%               ` [PATCH v8 4/4] " Thomas Gummerer
2018-04-24 21:56                   ` [PATCH v9 0/4] " Thomas Gummerer
2018-04-24 21:56  9%                 ` [PATCH v9 4/4] " Thomas Gummerer
2018-01-24  9:53     [PATCH 0/7] nd/worktree-move reboot Nguyễn Thái Ngọc Duy
2018-01-24  9:53  3% ` [PATCH 6/7] worktree remove: new command Nguyễn Thái Ngọc Duy
2018-02-12  9:49     ` [PATCH v2 0/7] nd/worktree-move reboot Nguyễn Thái Ngọc Duy
2018-02-12  9:49  3%   ` [PATCH v2 6/7] worktree remove: new command Nguyễn Thái Ngọc Duy
2018-01-28  0:36     [PATCH v2 0/1] setup: recognise extensions.objectFormat Patryk Obara
2018-01-28  0:36     ` [PATCH v2 1/1] " Patryk Obara
2018-01-30  1:38  4%   ` Jeff King
2018-02-22 19:29     [PATCH] sequencer: factor out strbuf_read_file_or_whine() René Scharfe
2018-02-23  6:49     ` Jeff King
2018-02-23  7:00       ` [PATCH] strbuf_read_file(): preserve errno across close() call Jeff King
2018-02-23 21:00         ` René Scharfe
2018-02-23 22:17  4%       ` Junio C Hamano
2018-02-23 22:55  0%         ` René Scharfe
2018-03-17  7:53     [PATCH 00/36] Combine t/helper binaries into a single one Nguyễn Thái Ngọc Duy
2018-03-17  7:53  4% ` [PATCH 01/36] t/helper: add an empty test-tool program Nguyễn Thái Ngọc Duy
2018-03-24  7:42     ` [PATCH v2 00/36] Combine t/helper binaries into a single one Nguyễn Thái Ngọc Duy
2018-03-24  7:42  4%   ` [PATCH v2 01/36] t/helper: add an empty test-tool program Nguyễn Thái Ngọc Duy
2018-03-24  7:44     ` [PATCH v2 00/36] Combine t/helper binaries into a single one Nguyễn Thái Ngọc Duy
2018-03-24  7:44  4%   ` [PATCH v2 01/36] t/helper: add an empty test-tool program Nguyễn Thái Ngọc Duy
2018-03-28  5:55  1% [PATCH] l10n: de.po: translate 132 new messages Ralf Thielow
2018-04-17 18:13  3% [PATCH/RFC] completion: complete all possible -no-<options> Nguyễn Thái Ngọc Duy
2018-04-23  5:36  0% ` Eric Sunshine
2018-05-24  7:04     [PATCH 0/5] Modernize some testcases for merge-recursive corner cases Elijah Newren
2018-05-24  7:04  3% ` [PATCH 1/5] t6036, t6042: use test_create_repo to keep tests independent Elijah Newren
2018-05-24  7:04  5% ` [PATCH 3/5] t6036, t6042: prefer test_path_is_file, test_path_is_missing Elijah Newren
2018-05-31 16:38     is there a reason pre-commit.sample uses "git diff-index"? Robert P. J. Day
2018-05-31 17:05     ` Duy Nguyen
2018-05-31 17:27       ` Robert P. J. Day
2018-05-31 23:08         ` Johannes Sixt
2018-05-31 23:09           ` Robert P. J. Day
2018-05-31 23:25  4%         ` Stefan Beller
2018-07-19 17:15  1% [PATCH] l10n: de.po: translate 108 new messages Ralf Thielow
2018-07-23 19:12  0% ` Matthias Rüster
2018-08-17 19:03  1% [RFC/PATCH] drop vcs-svn experiment Jeff King
2018-08-26 10:02     [PATCH 00/21] Kill the_index part 4 Nguyễn Thái Ngọc Duy
2018-08-26 10:03  4% ` [PATCH 11/21] merge.c: remove implicit dependency on the_index Nguyễn Thái Ngọc Duy
2018-09-03 18:09     ` [PATCH v2 00/24] Kill the_index part 4 Nguyễn Thái Ngọc Duy
2018-09-03 18:09  4%   ` [PATCH v2 13/24] merge.c: remove implicit dependency on the_index Nguyễn Thái Ngọc Duy
2018-09-09  8:53       ` [PATCH v3 00/23] Kill the_index part 4 Nguyễn Thái Ngọc Duy
2018-09-09  8:54  4%     ` [PATCH v3 13/23] merge.c: remove implicit dependency on the_index Nguyễn Thái Ngọc Duy
2018-09-15 16:17         ` [PATCH v4 00/23] Kill the_index part 4 Nguyễn Thái Ngọc Duy
2018-09-15 16:17  4%       ` [PATCH v4 13/23] merge.c: remove implicit dependency on the_index Nguyễn Thái Ngọc Duy
2018-09-21 15:57           ` [PATCH v5 00/23] Kill the_index part 4 Nguyễn Thái Ngọc Duy
2018-09-21 15:57  4%         ` [PATCH v5 13/23] merge.c: remove implicit dependency on the_index Nguyễn Thái Ngọc Duy
2018-10-10 15:09     [PATCH] range-diff: allow to diff files regardless submodule Lucas De Marchi
2018-10-11  0:02     ` brian m. carlson
2018-10-11  7:50       ` Lucas De Marchi
2018-10-12  9:24  4%     ` Johannes Schindelin
2018-10-15 13:01     Ignored files being silently overwritten when switching branches Per Lundberg
2018-10-16  6:40     ` Jeff King
2010-08-20 20:35       ` [PATCH] optionally disable overwriting of ignored files Junio C Hamano
2010-08-23  9:37         ` Matthieu Moy
2018-10-16  9:10  3%       ` Ignored files being silently overwritten when switching branches Ævar Arnfjörð Bjarmason
2018-10-16 15:05  4%         ` Duy Nguyen
2018-10-18  1:55  4%           ` Junio C Hamano
2018-11-11  9:52 20% [RFC PATCH] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
2018-11-06 15:12     ` Checkout deleted semi-untracked file Ævar Arnfjörð Bjarmason
2018-11-11 12:33 11%   ` [RFC PATCH] Introduce "precious" file concept Ævar Arnfjörð Bjarmason
2018-11-11 13:06  4%     ` Ævar Arnfjörð Bjarmason
2018-11-12 16:14  6%       ` Duy Nguyen
2018-11-11 15:41 11%     ` Duy Nguyen
2018-11-11 16:55  5%       ` Ævar Arnfjörð Bjarmason
2018-11-12  7:35 11%       ` Per Lundberg
2018-11-12  9:08 12%         ` Matthieu Moy
2018-11-12  9:49  4%           ` Ævar Arnfjörð Bjarmason
2018-11-12 10:26  6%             ` Junio C Hamano
2018-11-12 12:45  6%               ` Ævar Arnfjörð Bjarmason
2018-11-12 13:02  6%                 ` Junio C Hamano
2018-11-12 16:07  5%           ` Duy Nguyen
2018-11-12 23:22  5%     ` brian m. carlson
2018-11-26  9:30  5%       ` Per Lundberg
2018-11-26 10:28  5%         ` Ævar Arnfjörð Bjarmason
2018-11-26 12:49 12%         ` Junio C Hamano
2018-11-27 15:08 10%           ` Ævar Arnfjörð Bjarmason
2018-11-28  3:58  5%             ` Junio C Hamano
2018-11-28 21:54  5%               ` Ævar Arnfjörð Bjarmason
2018-11-29  5:04 10%                 ` Junio C Hamano
2018-12-01  6:21  5%                 ` Duy Nguyen
2018-11-26 15:26 11%         ` Duy Nguyen
2018-11-26 15:34  6%           ` Ævar Arnfjörð Bjarmason
2018-11-26 15:40  6%             ` Duy Nguyen
2018-11-26 15:47  6%               ` Ævar Arnfjörð Bjarmason
2018-11-26 15:55 11%                 ` Duy Nguyen
2018-11-27  9:43 11%                   ` Per Lundberg
2018-11-27 12:55 10%                     ` Jacob Keller
2018-11-27 14:50  4%                       ` Per Lundberg
2018-11-28  1:21  4%                         ` brian m. carlson
2018-11-28  6:54  5%                           ` Per Lundberg
2018-11-27 15:19  6%                       ` Duy Nguyen
2018-12-06 18:39 10%                       ` Duy Nguyen
2018-11-26 16:02  6%       ` Eckhard Maaß
2018-11-11 12:15 11% ` Bert Wesarg
2018-11-11 12:59 12% ` Junio C Hamano
2018-11-26 19:38  6% ` [PATCH v2 0/2] Precios files round two Nguyễn Thái Ngọc Duy
2018-11-26 19:38 19%   ` [PATCH v2 1/2] Introduce "precious" file concept Nguyễn Thái Ngọc Duy
2018-11-26 19:38 17%   ` [PATCH v2 2/2] unpack-trees: support core.allIgnoredFilesArePreciousWhenMerging Nguyễn Thái Ngọc Duy
2018-11-24  2:35     git overwriting local ignored files? David Mandelberg
2018-11-24  4:22  4% ` Junio C Hamano
2018-11-24 14:37  6%   ` David Mandelberg
2018-11-24 14:57  0%     ` Konstantin Khomoutov
2018-11-24 15:41  0%       ` Konstantin Khomoutov
2018-11-25  2:06  0%         ` David Mandelberg
2018-11-27 16:52     Git pull confusing output Will
2018-11-27 19:24  3% ` Stefan Beller
2018-11-27 22:34  0%   ` Will
2018-11-27 23:37  0%     ` Ævar Arnfjörð Bjarmason
2018-11-28 21:52     [PATCH 0/5] Add a new "sparse" tree walk algorithm Derrick Stolee via GitGitGadget
2018-11-28 21:52     ` [PATCH 3/5] pack-objects: add --sparse option Derrick Stolee via GitGitGadget
2018-11-28 22:11       ` Stefan Beller
2018-11-29 14:20         ` Derrick Stolee
2018-11-30  2:39  4%       ` Junio C Hamano
2018-12-01 22:51     [RFC] git clean --local Cameron Boehmer
2018-12-02  0:04  4% ` Junio C Hamano
2018-12-02  4:43  7%   ` Junio C Hamano
2018-12-02 13:25     ` Ævar Arnfjörð Bjarmason
2018-12-02 17:37  4%   ` Randall S. Becker
2018-12-02 19:37  4%     ` Junio C Hamano
2018-12-03  7:40  0%       ` Cameron Boehmer
2018-12-04  2:45  7%       ` Junio C Hamano
2018-12-09 10:43  3% [RFC PATCH 00/24] Add backup log Nguyễn Thái Ngọc Duy
2018-12-09 10:44  7% ` [PATCH 19/24] unpack-trees.c: keep backup of ignored files being overwritten Nguyễn Thái Ngọc Duy
2018-12-09 10:44  6% ` [PATCH 24/24] FIXME Nguyễn Thái Ngọc Duy
2018-12-16 12:12  4% [PATCH] worktree: allow to (re)move worktrees with uninitialized submodules Nguyễn Thái Ngọc Duy
2018-12-16 14:46  3% ` [PATCH v2] " Nguyễn Thái Ngọc Duy
2019-01-04 22:51  0%   ` Junio C Hamano
2019-01-05  5:08  3%   ` [PATCH v3] " Nguyễn Thái Ngọc Duy
2019-01-16 10:31     [RFC/PATCH 00/10] Support using submodules with worktrees Nguyễn Thái Ngọc Duy
2019-01-16 10:31  3% ` [PATCH 01/10] doc: about submodule support with multiple worktrees Nguyễn Thái Ngọc Duy
2019-01-16 22:06  0%   ` Stefan Beller
2019-01-28  2:41     There should be a `.gitbless; file, protecting files from git clean Sebastian Gniazdowski
2019-01-28  5:05  4% ` Duy Nguyen
2019-01-28  5:24  4%   ` Sebastian Gniazdowski

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).