* Re: 4-way diff (base,ours,theirs,merged) to review merge results
From: Junio C Hamano @ 2012-02-26 8:12 UTC (permalink / raw)
To: Neal Kreitzinger; +Cc: git
In-Reply-To: <jicafn$gnj$1@dough.gmane.org>
"Neal Kreitzinger" <neal@rsss.com> writes:
> (Combined diff)
> ours: has line-x
> theirs (master): does not have line-x
> merged: has line-x
> merge-base (older master): *may-or-may-not* have line-x
> conclusion: I'm not very sure if "merged" should have line-x or not...
When I need this information to resolve a merge in an area of the code
that I am not very familiar with, the first thing I do is this:
$ git merge $other
$ git diff
... yikes, that is a complex conflict!
$ git checkout --conflict=diff3 $the_path_with_difficult_conflict
$ git diff
The output will also show the lines from the merge base.
The default style of showing the conflict we use is called the "merge"
style (it originally came from the "merge" program of the RCS suite), and
it only gives the two sides without the base version. It is sufficient
when the person who is making the merge is familiar with the baseline
history of the code (e.g. in a contributor-to-integrator pull based
workflow, especially when contributors are encouraged to keep their topics
focused and short). The "diff3" style that also gives the base version is
needed less often in such a setting. That, and also the resulting output
is much shorter, is the reason why "merge" style is the default.
When the person who is making the merge is not very familiar with the
baseline history (e.g. when using Git as an improved CVS and a contributor
pulls the updated upstream into his history), however, "diff3" style may
be more often helpful---as you mentioned, "merge" style requires that you
know your code well enough to either already know or be able to guess how
the version in the merge base looked like, but by definition, pulling the
updated upstream into your work will pull more stuff (because many other
people are working on the code on the other side) than pulling one topic
from a contributor into the integrator tree, so there may be more need to
see the version from the merge base in such a workflow.
By setting the configuration variable "merge.conflictstyle" to "diff3",
you would get the base version by default whenever there is a conflict.
^ permalink raw reply
* Re: [PATCH 2/2] index-pack: reduce memory usage when the pack has large blobs
From: Nguyen Thai Ngoc Duy @ 2012-02-26 4:10 UTC (permalink / raw)
To: Ian Kumlien; +Cc: git
In-Reply-To: <20120225224533.GJ9526@pomac.netswarm.net>
On Sun, Feb 26, 2012 at 5:45 AM, Ian Kumlien <pomac@vapor.com> wrote:
> Actually, i added a backtrace and used addr2line to confirm my
> suspicion... which is:
> builtin/index-pack.c:414
>
> ie get_data_from_pack...
That function should only be called when objects are deltified, which
should _not_ happen for large blobs. What is its caller?
>
> It looks to me like, if we are to support this kind of things, we need a
> slightly different approach - instead of passing the data around, it
> feels like passing a function pointer around would be beneficial.
>
> Looking at the code i see alot of places where this would be a issue,
> just the fact that get_data_from_pack is used in several functions that
> might do some small operation and then just free it.
>
> I understand and recognize that my "problem" is not what git was
> designed for; it was designed for small files, which is very evident in
> how it approaches the data... And I'd most definetly have to look alot
> closer to this code... =)
>
>> --
>> Duy
--
Duy
^ permalink raw reply
* 4-way diff (base,ours,theirs,merged) to review merge results
From: Neal Kreitzinger @ 2012-02-26 3:55 UTC (permalink / raw)
To: git
Combined diff only tells you what the merge result auto-resolved (with
rerere turned off and no merge-conflicts) in comparison to "ours" and
"theirs". That only tells you what "ours" and "theirs" *had*, not what they
*did* (or were trying to do). You need the merge-base version to see what
"ours" and "theirs" did. Seeing what "ours" and "theirs" did will
much-better tell you if "merged" did-the-right-thing or not. What is the
best way to display a 4-way diff of merge-base, "ours", "theirs", and
"merged" after a merge completes so you can review the "merged" results for
correctness?
Before I try writing a script to dump the object-contents of the merge-base,
"ours", "theirs", and "merged" versions of the-file-in-question to
work-files and then feed them to a 4-way diff for review, I would like to
see if someone already has a script or better-idea for this, or if git has
something more straight-forward that already does-this-for-you.
Reason for this:
If "ours" has line-x and "theirs" does not have line-x, and "merged" does
have line-x you still have a mystery on your hands:
(Combined diff)
ours: has line-x
theirs (master): does not have line-x
merged: has line-x
merge-base (older master): *may-or-may-not* have line-x
conclusion: I'm not very sure if "merged" should have line-x or not...
Based on the combined-diff only, I don't know if "merged" should have line-x
or not because I don't know if "ours" *added* line-x to the merge-base or if
"theirs" *removed* line-x from the merge-base. IOW, if "theirs" is master
and "ours" is way-behind master then I pretty-much know I probably need to
take "theirs" because it has the latest-stuff. However, I don't know if
"theirs" took line-x out of master (and "ours" just has line-x because its
old), or if line-x was never in master and "ours" really-needed to add it.
Having merge-base context allows for more accurate conclusions like this:
ours: has line-x
theirs (master): does not have line-x
merged: has line-x
merge-base (older master): has line-x
conclusion: I should probably take line-x out of "merged"
ours: has line-x
theirs (master): does not have line-x
merged: has line-x
merge-base: does not have line-x
conclusion: I should probably keep line-x in "merged"
Thanks in advance for you feedback.
v/r,
neal
^ permalink raw reply
* [PATCH] Allow Overriding GIT_BUILD_DIR
From: David A. Greene @ 2012-02-05 22:28 UTC (permalink / raw)
To: git
Let tests override GIT_BUILD_DIR so git will work if tests are not at
the same directory level as standard git tests. Prior to this change,
GIT_BUILD_DIR is hardwired to be exactly one directory above where the
test lives. A test within contrib/, for example, can now use
test-lib.sh and set an appropriate value for GIT_BUILD_DIR.
Signed-off-by: David A. Greene <greened@obbligato.org>
---
t/test-lib.sh | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
------------------
diff --git a/t/test-lib.sh b/t/test-lib.sh
index a65dfc7..4585138 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -55,6 +55,7 @@ unset $(perl -e '
.*_TEST
PROVE
VALGRIND
+ BUILD_DIR
));
my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env);
print join("\n", @vars);
@@ -901,7 +902,14 @@ then
# itself.
TEST_DIRECTORY=$(pwd)
fi
-GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+
+if test -z "$GIT_BUILD_DIR"
+then
+ # We allow tests to override this, in case they want to run tests
+ # outside of t/, e.g. for running tests on the test library
+ # itself.
+ GIT_BUILD_DIR="$TEST_DIRECTORY"/..
+fi
if test -n "$valgrind"
then
--------------------
^ permalink raw reply related
* [PATCH 2/2] git-p4: fix submit regression with clientSpec and subdir clone
From: Pete Wyckoff @ 2012-02-26 1:06 UTC (permalink / raw)
To: git; +Cc: Laurent Charrière
In-Reply-To: <1330218385-22309-1-git-send-email-pw@padd.com>
When the --use-client-spec is given to clone, and the clone
path is a subset of the full tree as specified in the client,
future submits will go to the wrong place.
Factor out getClientSpec() so both clone/sync and submit can
use it. Introduce getClientRoot() that is needed for the client
spec case, and use it instead of p4Where().
Test the five possible submit behaviors (add, modify, rename,
copy, delete).
Reported-by: Laurent Charrière <lcharriere@promptu.com>
Signed-off-by: Pete Wyckoff <pw@padd.com>
---
contrib/fast-import/git-p4 | 86 ++++++++++++++++---------
t/t9809-git-p4-client-view.sh | 142 +++++++++++++++++++++++++++++++++++++---
2 files changed, 185 insertions(+), 43 deletions(-)
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 94f0a12..9ccc87b 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -555,6 +555,46 @@ def p4PathStartsWith(path, prefix):
return path.lower().startswith(prefix.lower())
return path.startswith(prefix)
+def getClientSpec():
+ """Look at the p4 client spec, create a View() object that contains
+ all the mappings, and return it."""
+
+ specList = p4CmdList("client -o")
+ if len(specList) != 1:
+ die('Output from "client -o" is %d lines, expecting 1' %
+ len(specList))
+
+ # dictionary of all client parameters
+ entry = specList[0]
+
+ # just the keys that start with "View"
+ view_keys = [ k for k in entry.keys() if k.startswith("View") ]
+
+ # hold this new View
+ view = View()
+
+ # append the lines, in order, to the view
+ for view_num in range(len(view_keys)):
+ k = "View%d" % view_num
+ if k not in view_keys:
+ die("Expected view key %s missing" % k)
+ view.append(entry[k])
+
+ return view
+
+def getClientRoot():
+ """Grab the client directory."""
+
+ output = p4CmdList("client -o")
+ if len(output) != 1:
+ die('Output from "client -o" is %d lines, expecting 1' % len(output))
+
+ entry = output[0]
+ if "Root" not in entry:
+ die('Client has no "Root"')
+
+ return entry["Root"]
+
class Command:
def __init__(self):
self.usage = "usage: %prog [options]"
@@ -1119,11 +1159,20 @@ class P4Submit(Command, P4UserMap):
print "Internal error: cannot locate perforce depot path from existing branches"
sys.exit(128)
- self.clientPath = p4Where(self.depotPath)
+ self.useClientSpec = False
+ if gitConfig("git-p4.useclientspec", "--bool") == "true":
+ self.useClientSpec = True
+ if self.useClientSpec:
+ self.clientSpecDirs = getClientSpec()
+
+ if self.useClientSpec:
+ # all files are relative to the client spec
+ self.clientPath = getClientRoot()
+ else:
+ self.clientPath = p4Where(self.depotPath)
- if len(self.clientPath) == 0:
- print "Error: Cannot locate perforce checkout of %s in client view" % self.depotPath
- sys.exit(128)
+ if self.clientPath == "":
+ die("Error: Cannot locate perforce checkout of %s in client view" % self.depotPath)
print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
self.oldWorkingDirectory = os.getcwd()
@@ -2078,33 +2127,6 @@ class P4Sync(Command, P4UserMap):
print self.gitError.read()
- def getClientSpec(self):
- specList = p4CmdList("client -o")
- if len(specList) != 1:
- die('Output from "client -o" is %d lines, expecting 1' %
- len(specList))
-
- # dictionary of all client parameters
- entry = specList[0]
-
- # just the keys that start with "View"
- view_keys = [ k for k in entry.keys() if k.startswith("View") ]
-
- # hold this new View
- view = View()
-
- # append the lines, in order, to the view
- for view_num in range(len(view_keys)):
- k = "View%d" % view_num
- if k not in view_keys:
- die("Expected view key %s missing" % k)
- view.append(entry[k])
-
- self.clientSpecDirs = view
- if self.verbose:
- for i, m in enumerate(self.clientSpecDirs.mappings):
- print "clientSpecDirs %d: %s" % (i, str(m))
-
def run(self, args):
self.depotPaths = []
self.changeRange = ""
@@ -2145,7 +2167,7 @@ class P4Sync(Command, P4UserMap):
if gitConfig("git-p4.useclientspec", "--bool") == "true":
self.useClientSpec = True
if self.useClientSpec:
- self.getClientSpec()
+ self.clientSpecDirs = getClientSpec()
# TODO: should always look at previous commits,
# merge with previous imports, if possible.
diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh
index 25e01a4..9642641 100755
--- a/t/t9809-git-p4-client-view.sh
+++ b/t/t9809-git-p4-client-view.sh
@@ -71,20 +71,24 @@ git_verify() {
# - dir2
# - file21
# - file22
+init_depot() {
+ for d in 1 2 ; do
+ mkdir -p dir$d &&
+ for f in 1 2 ; do
+ echo dir$d/file$d$f >dir$d/file$d$f &&
+ p4 add dir$d/file$d$f &&
+ p4 submit -d "dir$d/file$d$f"
+ done
+ done &&
+ find . -type f ! -name files >files &&
+ check_files_exist dir1/file11 dir1/file12 \
+ dir2/file21 dir2/file22
+}
+
test_expect_success 'init depot' '
(
cd "$cli" &&
- for d in 1 2 ; do
- mkdir -p dir$d &&
- for f in 1 2 ; do
- echo dir$d/file$d$f >dir$d/file$d$f &&
- p4 add dir$d/file$d$f &&
- p4 submit -d "dir$d/file$d$f"
- done
- done &&
- find . -type f ! -name files >files &&
- check_files_exist dir1/file11 dir1/file12 \
- dir2/file21 dir2/file22
+ init_depot
)
'
@@ -257,6 +261,122 @@ test_expect_success 'clone --use-client-spec sets useClientSpec' '
)
'
+# clone just a subdir of the client spec
+test_expect_success 'subdir clone' '
+ client_view "//depot/... //client/..." &&
+ files="dir1/file11 dir1/file12 dir2/file21 dir2/file22" &&
+ client_verify $files &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 &&
+ git_verify dir1/file11 dir1/file12
+'
+
+#
+# submit back, see what happens: five cases
+#
+test_expect_success 'subdir clone, submit modify' '
+ client_view "//depot/... //client/..." &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ echo line >>dir1/file12 &&
+ git add dir1/file12 &&
+ git commit -m dir1/file12 &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file dir1/file12 &&
+ test_line_count = 2 dir1/file12
+ )
+'
+
+test_expect_success 'subdir clone, submit add' '
+ client_view "//depot/... //client/..." &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ echo file13 >dir1/file13 &&
+ git add dir1/file13 &&
+ git commit -m dir1/file13 &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file dir1/file13
+ )
+'
+
+test_expect_success 'subdir clone, submit delete' '
+ client_view "//depot/... //client/..." &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git rm dir1/file12 &&
+ git commit -m "delete dir1/file12" &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing dir1/file12
+ )
+'
+
+test_expect_success 'subdir clone, submit copy' '
+ client_view "//depot/... //client/..." &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.detectCopies true &&
+ cp dir1/file11 dir1/file11a &&
+ git add dir1/file11a &&
+ git commit -m "copy to dir1/file11a" &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_file dir1/file11a
+ )
+'
+
+test_expect_success 'subdir clone, submit rename' '
+ client_view "//depot/... //client/..." &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 &&
+ (
+ cd "$git" &&
+ git config git-p4.skipSubmitEdit true &&
+ git config git-p4.detectRenames true &&
+ git mv dir1/file13 dir1/file13a &&
+ git commit -m "rename dir1/file13 to dir1/file13a" &&
+ "$GITP4" submit
+ ) &&
+ (
+ cd "$cli" &&
+ test_path_is_missing dir1/file13 &&
+ test_path_is_file dir1/file13a
+ )
+'
+
+test_expect_success 'reinit depot' '
+ (
+ cd "$cli" &&
+ p4 sync -f &&
+ rm files &&
+ p4 delete */* &&
+ p4 submit -d "delete all files" &&
+ init_depot
+ )
+'
+
#
# Rename directories to test quoting in depot-side mappings
# //depot
--
1.7.9.219.g1d56c.dirty
^ permalink raw reply related
* [PATCH 0/2] git-p4: fix submit regression with --use-client-spec
From: Pete Wyckoff @ 2012-02-26 1:06 UTC (permalink / raw)
To: git; +Cc: Laurent Charrière
This pair of patches fixes a regression that happened with ecb7cf9
(git-p4: rewrite view handling, 2012-01-02). There are two factors that
affect where files go in the client when submitting: the cilent spec,
and the depot path. When the depot path was not exactly the root of
the client, submit fails.
Fix this by always using the true client root. And also notice that
somebody has to tell the submit path that it should be looking at the
cilent spec. Save useClientSpec in a configuration variable if it
was specified as an option on the command line.
Junio: can you put this on maint to go out with the next 1.9.x?
Pete Wyckoff (2):
git-p4: set useClientSpec variable on initial clone
git-p4: fix submit regression with clientSpec and subdir clone
Documentation/git-p4.txt | 10 ++-
contrib/fast-import/git-p4 | 97 ++++++++++++++++---------
t/t9809-git-p4-client-view.sh | 159 ++++++++++++++++++++++++++++++++++++++---
3 files changed, 219 insertions(+), 47 deletions(-)
--
1.7.9.219.g1d56c.dirty
^ permalink raw reply
* [PATCH 1/2] git-p4: set useClientSpec variable on initial clone
From: Pete Wyckoff @ 2012-02-26 1:06 UTC (permalink / raw)
To: git; +Cc: Laurent Charrière
In-Reply-To: <1330218385-22309-1-git-send-email-pw@padd.com>
If --use-client-spec was given, set the matching configuration
variable. This is necessary to ensure that future submits
work properly.
The alternatives of requiring the user to set it, or providing
a command-line option on every submit, are error prone.
Signed-off-by: Pete Wyckoff <pw@padd.com>
---
Documentation/git-p4.txt | 10 +++++++---
contrib/fast-import/git-p4 | 11 ++++++++++-
t/t9809-git-p4-client-view.sh | 17 +++++++++++++++++
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt
index 78938b2..ed82790 100644
--- a/Documentation/git-p4.txt
+++ b/Documentation/git-p4.txt
@@ -303,9 +303,13 @@ CLIENT SPEC
-----------
The p4 client specification is maintained with the 'p4 client' command
and contains among other fields, a View that specifies how the depot
-is mapped into the client repository. Git-p4 can consult the client
-spec when given the '--use-client-spec' option or useClientSpec
-variable.
+is mapped into the client repository. The 'clone' and 'sync' commands
+can consult the client spec when given the '--use-client-spec' option or
+when the useClientSpec variable is true. After 'git p4 clone', the
+useClientSpec variable is automatically set in the repository
+configuration file. This allows future 'git p4 submit' commands to
+work properly; the submit command looks only at the variable and does
+not have a command-line option.
The full syntax for a p4 view is documented in 'p4 help views'. Git-p4
knows only a subset of the view syntax. It understands multi-line
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index 3e1aa27..94f0a12 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -1428,6 +1428,7 @@ class P4Sync(Command, P4UserMap):
self.p4BranchesInGit = []
self.cloneExclude = []
self.useClientSpec = False
+ self.useClientSpec_from_options = False
self.clientSpecDirs = None
if gitConfig("git-p4.syncFromOrigin") == "false":
@@ -2136,7 +2137,11 @@ class P4Sync(Command, P4UserMap):
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch):
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
- if not self.useClientSpec:
+ # accept either the command-line option, or the configuration variable
+ if self.useClientSpec:
+ # will use this after clone to set the variable
+ self.useClientSpec_from_options = True
+ else:
if gitConfig("git-p4.useclientspec", "--bool") == "true":
self.useClientSpec = True
if self.useClientSpec:
@@ -2455,6 +2460,10 @@ class P4Clone(P4Sync):
else:
print "Could not detect main branch. No checkout/master branch created."
+ # auto-set this variable if invoked with --use-client-spec
+ if self.useClientSpec_from_options:
+ system("git config --bool git-p4.useclientspec true")
+
return True
class P4Branches(Command):
diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh
index c9471d5..25e01a4 100755
--- a/t/t9809-git-p4-client-view.sh
+++ b/t/t9809-git-p4-client-view.sh
@@ -241,6 +241,23 @@ test_expect_success 'quotes on rhs only' '
'
#
+# Submit tests
+#
+
+# clone sets variable
+test_expect_success 'clone --use-client-spec sets useClientSpec' '
+ client_view "//depot/... //client/..." &&
+ test_when_finished cleanup_git &&
+ "$GITP4" clone --use-client-spec --dest="$git" //depot &&
+ (
+ cd "$git" &&
+ git config --bool git-p4.useClientSpec >actual &&
+ echo true >true &&
+ test_cmp actual true
+ )
+'
+
+#
# Rename directories to test quoting in depot-side mappings
# //depot
# - "dir 1"
--
1.7.9.219.g1d56c.dirty
^ permalink raw reply related
* Re: [PATCH 2/2] index-pack: reduce memory usage when the pack has large blobs
From: Ian Kumlien @ 2012-02-25 22:45 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <CACsJy8C-8dvXpNTU=JpdupSpS8OuqqTpGvDs6s1ASeKdk9d5Dg@mail.gmail.com>
On Sat, Feb 25, 2012 at 08:49:55AM +0700, Nguyen Thai Ngoc Duy wrote:
> 2012/2/24 Ian Kumlien <pomac@vapor.com>:
> > Writing objects: 100% (1425/1425), 56.06 MiB | 4.62 MiB/s, done.
> > Total 1425 (delta 790), reused 1425 (delta 790)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > To ../test_data/
> > ! [remote rejected] master -> master (missing necessary objects)
> > ! [remote rejected] origin/HEAD -> origin/HEAD (missing necessary objects)
> > ! [remote rejected] origin/master -> origin/master (missing necessary objects)
> > error: failed to push some refs to '../test_data/'
> >
> > So there are additional code paths to look at... =(
>
> I can't say where that came from. Does this help? (Space damaged, may
> need manual application)
> If not, you might need to apply this to generate coredump, then look
> and see where that failed malloc comes from
Actually, i added a backtrace and used addr2line to confirm my
suspicion... which is:
builtin/index-pack.c:414
ie get_data_from_pack...
It looks to me like, if we are to support this kind of things, we need a
slightly different approach - instead of passing the data around, it
feels like passing a function pointer around would be beneficial.
Looking at the code i see alot of places where this would be a issue,
just the fact that get_data_from_pack is used in several functions that
might do some small operation and then just free it.
I understand and recognize that my "problem" is not what git was
designed for; it was designed for small files, which is very evident in
how it approaches the data... And I'd most definetly have to look alot
closer to this code... =)
> --
> Duy
^ permalink raw reply
* [PATCH v4] Display change history as a diff between two dirs
From: Roland Kaufmann @ 2012-02-25 21:47 UTC (permalink / raw)
To: gitster; +Cc: git
Watching patches serially it can be difficult to get an overview of how
a pervasive change is distributed through-out different modules. Thus;
Extract snapshots of the files that have changed between two revisions
into temporary directories and launch a graphical tool to show the diff
between them.
Use existing functionality in git-diff to get the files themselves, and
git-difftool to launch the diff viewer.
Based on a script called 'git-diffc' by Nitin Gupta.
Signed-off-by: Roland Kaufmann <rlndkfmn+git@gmail.com>
---
Issue addressed in this revision:
* If changes were made in subdirectories the script though the diff
set between the two trees was empty, because it only checked for
regular files.
contrib/dirdiff/README | 10 ++++
contrib/dirdiff/git-dirdiff--helper.sh | 37 ++++++++++++++++
contrib/dirdiff/git-dirdiff.sh | 72 ++++++++++++++++++++++++++++++++
contrib/dirdiff/git-dirdiff.txt | 71 +++++++++++++++++++++++++++++++
4 files changed, 190 insertions(+), 0 deletions(-)
create mode 100644 contrib/dirdiff/README
create mode 100755 contrib/dirdiff/git-dirdiff--helper.sh
create mode 100755 contrib/dirdiff/git-dirdiff.sh
create mode 100644 contrib/dirdiff/git-dirdiff.txt
diff --git a/contrib/dirdiff/README b/contrib/dirdiff/README
new file mode 100644
index 0000000..d06461a
--- /dev/null
+++ b/contrib/dirdiff/README
@@ -0,0 +1,10 @@
+# install on GNU, BSD:
+for f in "" "--helper"; do
+ b=git-dirdiff$f
+ sudo install -m 0755 contrib/dirdiff/$b.sh $(git --exec-path)/$b
+done
+
+# install on Windows
+for /f %a in ('git --exec-path') do set GIT_PATH=%a
+set GIT_PATH=%GIT_PATH:/=\%
+for %a in ("" "--helper") do copy contrib\dirdiff\git-dirdiff%~a.sh "%GIT_PATH%\%~a" /y
diff --git a/contrib/dirdiff/git-dirdiff--helper.sh b/contrib/dirdiff/git-dirdiff--helper.sh
new file mode 100755
index 0000000..a23efee
--- /dev/null
+++ b/contrib/dirdiff/git-dirdiff--helper.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Accumulate files in a changeset into a pre-defined directory.
+#
+# Copyright (C) 2011-2012 Roland Kaufmann
+#
+# Based on a script called git-diffc by Nitin Gupta and valuable
+# suggestions by Junio C. Hamano.
+#
+# This file is licensed under the GPL v2, or a later version
+# at the discretion of the official Git maintainer.
+
+. git-sh-setup
+
+# check that we are called by git-dirdiff
+test -z "$__GIT_DIFF_DIR" &&
+ die Error: Do not call $(basename "$0") directly
+
+# what is the directory name of the file that has changed
+RELDIR=$(dirname "$1") ||
+ exit $?
+
+# don't attempt to copy new or removed files
+if test "$2" != "/dev/null"
+then
+ mkdir -p "$__GIT_DIFF_DIR/old/$RELDIR" ||
+ exit $?
+ cp "$2" "$__GIT_DIFF_DIR/old/$1" ||
+ exit $?
+fi
+if test "$5" != "/dev/null"
+then
+ mkdir -p "$__GIT_DIFF_DIR/new/$RELDIR" ||
+ exit $?
+ cp "$5" "$__GIT_DIFF_DIR/new/$1" ||
+ exit $?
+fi
diff --git a/contrib/dirdiff/git-dirdiff.sh b/contrib/dirdiff/git-dirdiff.sh
new file mode 100755
index 0000000..33c294d
--- /dev/null
+++ b/contrib/dirdiff/git-dirdiff.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+#
+# Display differences between two commits with a directory comparison.
+#
+# Copyright (C) 2011-2012 Roland Kaufmann
+#
+# Based on a script called git-diffc by Nitin Gupta and valuable
+# suggestions by Junio C. Hamano.
+#
+# This file is licensed under the GPL v2, or a later version
+# at the discretion of the official Git maintainer.
+
+. git-sh-setup
+
+# TMPDIR points to the designated space for temporary files; only if
+# not set use /tmp (MSYS even mounts %TEMP% to there)
+test -z "$TMPDIR" && TMPDIR=/tmp
+
+# create a temporary directory to hold snapshots of changed files
+# fallback on crippled platforms is to use a Perl module
+case $(uname -s) in
+Linux | *BSD | Darwin | windows* | CYGWIN_NT*)
+ __GIT_DIFF_DIR=$(mktemp -d "$TMPDIR/git-dirdiff.XXXXXX")
+ ;;
+*)
+ __GIT_DIFF_DIR=$(perl -e "use File::Temp qw/tempdir/; print tempdir(\"git-dirdiff.XXXXXX\", DIR=>\"$TMPDIR\")")
+ ;;
+esac
+test -d "$__GIT_DIFF_DIR" -a -w "$__GIT_DIFF_DIR" ||
+ die Error: Could not create a temporary subdir in $TMPDIR
+
+# cleanup after we're done
+trap 'rm -rf $__GIT_DIFF_DIR' 0
+
+# export this variable so that scripts called indirectly can access it
+export __GIT_DIFF_DIR
+
+# let the helper script accumulate all changed files into the temporary
+# directory letting 'git diff' do all the heavy lifting
+GIT_EXTERNAL_DIFF=git-dirdiff--helper git --no-pager diff "$@" ||
+ exit $?
+
+# first and second argument will always be the special directory links
+# if there are no hidden files nor regular files, then $3 will be the
+# second wildcard unexpanded
+isempty () {
+ set - $1/.* $1/*
+ test ! -e "$3"
+}
+
+# no-op if no files were changed
+isempty "$__GIT_DIFF_DIR/old" && isempty "$__GIT_DIFF_DIR/new" &&
+ exit 0
+
+# if a different tool is setup for tree comparison, launch that instead
+# if GIT_EXTERNAL_TREEDIFF is not set, then use GIT_EXTERNAL_DIFF
+if test -n "$GIT_EXTERNAL_DIFF"
+then
+ GIT_DIFFTOOL_EXTCMD=$GIT_EXTERNAL_DIFF
+ export GIT_DIFFTOOL_EXTCMD
+fi
+if test -n "$GIT_EXTERNAL_TREEDIFF"
+then
+ GIT_DIFFTOOL_EXTCMD=$GIT_EXTERNAL_TREEDIFF
+ export GIT_DIFFTOOL_EXTCMD
+fi
+
+# run original diff program, reckoning it will understand directories
+# modes and shas does not apply to the root directories so submit dummy
+# values for those, hoping that the diff tool does not use them.
+git-difftool--helper - "$__GIT_DIFF_DIR/old" deadbeef 0755 "$__GIT_DIFF_DIR/new" babeface 0755 ||
+ exit $?
diff --git a/contrib/dirdiff/git-dirdiff.txt b/contrib/dirdiff/git-dirdiff.txt
new file mode 100644
index 0000000..b80430a
--- /dev/null
+++ b/contrib/dirdiff/git-dirdiff.txt
@@ -0,0 +1,71 @@
+git-dirdiff(1)
+==============
+
+NAME
+----
+git-dirdiff - Show changes using directory compare
+
+SYNOPSIS
+--------
+[verse]
+'git dirdiff' [<options>] [<commit> [<commit>]] [--] [<path>...]
+
+DESCRIPTION
+-----------
+'git dirdiff' is a git command that allows you to compare revisions
+as a difference between two directories. 'git dirdiff' is a frontend
+to linkgit:git-diff[1].
+
+OPTIONS
+-------
+See linkgit:git-diff[1] for the list of supported options.
+
+ENVIRONMENT VARIABLES
+---------------------
+'GIT_EXTERNAL_TREEDIFF'::
+ When 'GIT_EXTERNAL_TREEDIFF' is set, the program named by it is
+ used as a diff viewer. The program must accept 7 parameters, where
+ parameter 2 is the path to a temporary directory containing the
+ "old" revision, and parameter 5 is the path of the "new" revision.
+ The other five parameters will only contain dummy values, and their
+ contents are subject to change.
+
+'GIT_EXTERNAL_DIFF'::
+ If and only if 'GIT_EXTERNAL_TREEDIFF' is not set, 'git dirdiff'
+ will use the contents of 'GIT_EXTERNAL_DIFF' as the name of the
+ diff viewer.
+
+CONFIG VARIABLES
+----------------
+If none of the above environment variables are set, 'git dirdiff' will
+use the same config variables as linkgit:git-difftool[1] to determine
+which difftool should be used.
+
+TEMPORARY FILES
+---------------
+'git dirdiff' creates a directory with 'mktemp' to hold snapshots of the
+files which are different in the two revisions. This directory is removed
+when the diff viewer terminates.
+
+NOTES
+-----
+The diff viewer must support being passed directories instead of files
+as its arguments.
++
+Files that are not put under version control are not included when
+viewing the difference between a revision and the working directory.
+
+SEE ALSO
+--------
+linkgit:git-diff[1]::
+ Show changes between commits, commit and working tree, etc
+
+linkgit:git-difftool[1]::
+ Show changes using common diff tools
+
+linkgit:git-config[1]::
+ Get and set repository or global options
+
+GIT
+---
+Part of the linkgit:git[1] suite
--
1.7.1
^ permalink raw reply related
* [PATCH] rebase -m: only call "notes copy" when rewritten exists and is non-empty
From: Andrew Wong @ 2012-02-25 4:31 UTC (permalink / raw)
To: git; +Cc: Andrew Wong
This prevents a shell error complaining rebase-merge/rewritten doesn't exist.
Signed-off-by: Andrew Wong <andrew.kw.w@gmail.com>
---
git-rebase--merge.sh | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index 26afc75..5e9d95f 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -90,10 +90,11 @@ call_merge () {
finish_rb_merge () {
move_to_original_branch
- git notes copy --for-rewrite=rebase < "$state_dir"/rewritten
- if test -x "$GIT_DIR"/hooks/post-rewrite &&
- test -s "$state_dir"/rewritten; then
- "$GIT_DIR"/hooks/post-rewrite rebase < "$state_dir"/rewritten
+ if test -s "$state_dir"/rewritten; then
+ git notes copy --for-rewrite=rebase < "$state_dir"/rewritten
+ if test -x "$GIT_DIR"/hooks/post-rewrite; then
+ "$GIT_DIR"/hooks/post-rewrite rebase < "$state_dir"/rewritten
+ fi
fi
rm -r "$state_dir"
say All done.
--
1.7.9.2.263.g07763
^ permalink raw reply related
* [PATCH 0/3] parse-options: no- symmetry
From: René Scharfe @ 2012-02-25 19:07 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bert Wesarg, Geoffrey Irving, Johannes Schindelin,
Pierre Habouzit
Boolean long options can be negated by adding a "no-" at the
beginning, unless the flag PARSE_OPT_NONEG is set. There are
several options defined to start out with "no-" already (e.g.
format-patch --no-numbered). Their negation with a second
"no-" looks a bit strange.
The flag PARSE_OPT_NEGHELP was introduced to avoid this
awkwardness. It is used twice (in fast-export and grep) to
define option pairs (--data/--no-data and --index/--no-index)
whose negative part is shown in the help text.
However, PARSE_OPT_NEGHELP is strange as well. Short options
defined with it do the opposite of what the help text says
(we currently don't have any). And the multiple negations
are confusing.
This series adds the ability for users to negate options that
already start with "no-" by simply leaving it out. The last
patch removes PARSE_OPT_NEGHELP as it isn't needed anymore at
that point.
test-parse-options: convert to OPT_BOOL()
parse-options: allow positivation of options starting with no-
parse-options: remove PARSE_OPT_NEGHELP
Documentation/technical/api-parse-options.txt | 3 +-
builtin/fast-export.c | 4 +-
builtin/grep.c | 15 +++----
parse-options.c | 33 ++++++++------
parse-options.h | 4 --
t/t0040-parse-options.sh | 60 ++++++++++++++++++++++++-
test-parse-options.c | 12 +++--
7 files changed, 95 insertions(+), 36 deletions(-)
--
1.7.9.2
^ permalink raw reply
* [PATCH 1/3] test-parse-options: convert to OPT_BOOL()
From: René Scharfe @ 2012-02-25 19:11 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bert Wesarg, Geoffrey Irving, Johannes Schindelin,
Pierre Habouzit
In-Reply-To: <4F49317A.3080809@lsrfire.ath.cx>
Introduce OPT_BOOL() to test-parse-options and add some tests for
these "true" boolean options. Rename OPT_BOOLEAN to OPT_COUNTUP and
OPTION_BOOLEAN to OPTION_COUNTUP as well.
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
t/t0040-parse-options.sh | 60 ++++++++++++++++++++++++++++++++++++++++++++--
test-parse-options.c | 12 ++++++----
2 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index a1e4616..79aefe2 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -10,7 +10,10 @@ test_description='our own option parser'
cat > expect << EOF
usage: test-parse-options <options>
- -b, --boolean get a boolean
+ --yes get a boolean
+ -D, --no-doubt begins with 'no-'
+ -B, --no-fear be brave
+ -b, --boolean increment by one
-4, --or4 bitwise-or boolean with ...0100
--neg-or4 same as --no-or4
@@ -53,6 +56,59 @@ test_expect_success 'test help' '
mv expect expect.err
+cat >expect.template <<EOF
+boolean: 0
+integer: 0
+timestamp: 0
+string: (not set)
+abbrev: 7
+verbose: 0
+quiet: no
+dry run: no
+file: (not set)
+EOF
+
+check() {
+ what="$1" &&
+ shift &&
+ expect="$1" &&
+ shift &&
+ sed "s/^$what .*/$what $expect/" <expect.template >expect &&
+ test-parse-options $* >output 2>output.err &&
+ test ! -s output.err &&
+ test_cmp expect output
+}
+
+check_unknown() {
+ case "$1" in
+ --*)
+ echo error: unknown option \`${1#--}\' >expect ;;
+ -*)
+ echo error: unknown switch \`${1#-}\' >expect ;;
+ esac &&
+ cat expect.err >>expect &&
+ test_must_fail test-parse-options $* >output 2>output.err &&
+ test ! -s output &&
+ test_cmp expect output.err
+}
+
+test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes'
+test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt'
+test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D'
+test_expect_success 'OPT_BOOL() #4' 'check boolean: 1 --no-fear'
+test_expect_success 'OPT_BOOL() #5' 'check boolean: 1 -B'
+
+test_expect_success 'OPT_BOOL() is idempotent #1' 'check boolean: 1 --yes --yes'
+test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB'
+
+test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes'
+test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
+
+test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
+test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
+
+test_expect_failure 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
+
cat > expect << EOF
boolean: 2
integer: 1729
@@ -296,7 +352,7 @@ test_expect_success 'OPT_NEGBIT() works' '
test_cmp expect output
'
-test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' '
+test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
test-parse-options + + + + + + > output 2> output.err &&
test ! -s output.err &&
test_cmp expect output
diff --git a/test-parse-options.c b/test-parse-options.c
index 36487c4..3c9510a 100644
--- a/test-parse-options.c
+++ b/test-parse-options.c
@@ -37,7 +37,11 @@ int main(int argc, const char **argv)
NULL
};
struct option options[] = {
- OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"),
+ OPT_BOOL(0, "yes", &boolean, "get a boolean"),
+ OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"),
+ { OPTION_SET_INT, 'B', "no-fear", &boolean, NULL,
+ "be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
+ OPT_COUNTUP('b', "boolean", &boolean, "increment by one"),
OPT_BIT('4', "or4", &boolean,
"bitwise-or boolean with ...0100", 4),
OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4),
@@ -62,11 +66,11 @@ int main(int argc, const char **argv)
OPT_ARGUMENT("quux", "means --quux"),
OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
number_callback),
- { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b",
+ { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH },
- { OPTION_BOOLEAN, 0, "ambiguous", &ambiguous, NULL,
+ { OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL,
"positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG },
- { OPTION_BOOLEAN, 0, "no-ambiguous", &ambiguous, NULL,
+ { OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL,
"negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG },
OPT_GROUP("Standard options"),
OPT__ABBREV(&abbrev),
--
1.7.9.2
^ permalink raw reply related
* [PATCH 3/3] parse-options: remove PARSE_OPT_NEGHELP
From: René Scharfe @ 2012-02-25 19:15 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bert Wesarg, Geoffrey Irving, Johannes Schindelin,
Pierre Habouzit
In-Reply-To: <4F49317A.3080809@lsrfire.ath.cx>
PARSE_OPT_NEGHELP is confusing because short options defined with that
flag do the opposite of what the helptext says. It is also not needed
anymore now that options starting with no- can be negated by removing
that prefix. Convert its only two users to OPT_BOOL() and then remove
support for PARSE_OPT_NEGHELP.
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
builtin/fast-export.c | 4 +---
builtin/grep.c | 15 +++++++--------
parse-options.c | 6 ++----
parse-options.h | 4 ----
4 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 08fed98..19509ea 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -647,9 +647,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Output full tree for each commit"),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
"Use the done feature to terminate the stream"),
- { OPTION_NEGBIT, 0, "data", &no_data, NULL,
- "Skip output of blob data",
- PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
+ OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
OPT_END()
};
diff --git a/builtin/grep.c b/builtin/grep.c
index e4ea900..b151467 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -671,7 +671,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
struct string_list path_list = STRING_LIST_INIT_NODUP;
int i;
int dummy;
- int use_index = 1;
+ int no_index = 0;
enum {
pattern_type_unspecified = 0,
pattern_type_bre,
@@ -684,9 +684,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
"search in index instead of in the work tree"),
- { OPTION_BOOLEAN, 0, "index", &use_index, NULL,
- "finds in contents not managed by git",
- PARSE_OPT_NOARG | PARSE_OPT_NEGHELP },
+ OPT_BOOL(0, "no-index", &no_index,
+ "finds in contents not managed by git"),
OPT_BOOLEAN(0, "untracked", &untracked,
"search in both tracked and untracked files"),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
@@ -851,7 +850,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
break; /* nothing */
}
- if (use_index && !startup_info->have_repository)
+ if (!no_index && !startup_info->have_repository)
/* die the same way as if we did it at the beginning */
setup_git_directory();
@@ -963,11 +962,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
if (!show_in_pager)
setup_pager();
- if (!use_index && (untracked || cached))
+ if (no_index && (untracked || cached))
die(_("--cached or --untracked cannot be used with --no-index."));
- if (!use_index || untracked) {
- int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
+ if (no_index || untracked) {
+ int use_exclude = (opt_exclude < 0) ? !no_index : !!opt_exclude;
if (list.nr)
die(_("--no-index or --untracked cannot be used with revs."));
hit = grep_directory(&opt, &pathspec, use_exclude);
diff --git a/parse-options.c b/parse-options.c
index 8906841..1908996 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -533,7 +533,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
continue;
pos = fprintf(outfile, " ");
- if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {
+ if (opts->short_name) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(outfile, "%c", opts->short_name);
else
@@ -542,9 +542,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
if (opts->long_name && opts->short_name)
pos += fprintf(outfile, ", ");
if (opts->long_name)
- pos += fprintf(outfile, "--%s%s",
- (opts->flags & PARSE_OPT_NEGHELP) ? "no-" : "",
- opts->long_name);
+ pos += fprintf(outfile, "--%s", opts->long_name);
if (opts->type == OPTION_NUMBER)
pos += fprintf(outfile, "-NUM");
diff --git a/parse-options.h b/parse-options.h
index 2e811dc..def9ced 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -40,7 +40,6 @@ enum parse_opt_option_flags {
PARSE_OPT_LASTARG_DEFAULT = 16,
PARSE_OPT_NODASH = 32,
PARSE_OPT_LITERAL_ARGHELP = 64,
- PARSE_OPT_NEGHELP = 128,
PARSE_OPT_SHELL_EVAL = 256
};
@@ -90,9 +89,6 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
* PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
* (i.e. '<argh>') in the help message.
* Useful for options with multiple parameters.
- * PARSE_OPT_NEGHELP: says that the long option should always be shown with
- * the --no prefix in the usage message. Sometimes
- * useful for users of OPTION_NEGBIT.
*
* `callback`::
* pointer to the callback to use for OPTION_CALLBACK or
--
1.7.9.2
^ permalink raw reply related
* [PATCH 2/3] parse-options: allow positivation of options starting, with no-
From: René Scharfe @ 2012-02-25 19:14 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Bert Wesarg, Geoffrey Irving, Johannes Schindelin,
Pierre Habouzit
In-Reply-To: <4F49317A.3080809@lsrfire.ath.cx>
Long options can be negated by adding no- right after the leading
two dashes. This is useful e.g. to override options set by aliases.
For options that are defined to start with no- already, this looks
a bit funny. Allow such options to also be negated by removing the
prefix.
The following thirteen options are affected:
apply --no-add
bisect--helper --no-checkout
checkout-index --no-create
clone --no-checkout --no-hardlinks
commit --no-verify --no-post-rewrite
format-patch --no-binary
hash-object --no-filters
read-tree --no-sparse-checkout
revert --no-commit
show-branch --no-name
update-ref --no-deref
The following five are NOT affected because they are defined with
PARSE_OPT_NONEG or the non-negated version is defined as well:
branch --no-merged
format-patch --no-stat --no-numbered
update-index --no-assume-unchanged --no-skip-worktree
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
Documentation/technical/api-parse-options.txt | 3 ++-
parse-options.c | 27 ++++++++++++++++---------
t/t0040-parse-options.sh | 2 +-
3 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 4b92514..2527b7e 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -39,7 +39,8 @@ The parse-options API allows:
* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
* Boolean long options can be 'negated' (or 'unset') by prepending
- `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`.
+ `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`. Conversely,
+ options that begin with `no-` can be 'negated' by removing it.
* Options and non-option arguments can clearly be separated using the `\--`
option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that
diff --git a/parse-options.c b/parse-options.c
index f0098eb..8906841 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -193,13 +193,14 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
arg_end = arg + strlen(arg);
for (; options->type != OPTION_END; options++) {
- const char *rest;
- int flags = 0;
+ const char *rest, *long_name = options->long_name;
+ int flags = 0, opt_flags = 0;
- if (!options->long_name)
+ if (!long_name)
continue;
- rest = skip_prefix(arg, options->long_name);
+again:
+ rest = skip_prefix(arg, long_name);
if (options->type == OPTION_ARGUMENT) {
if (!rest)
continue;
@@ -212,7 +213,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
}
if (!rest) {
/* abbreviated? */
- if (!strncmp(options->long_name, arg, arg_end - arg)) {
+ if (!strncmp(long_name, arg, arg_end - arg)) {
is_abbreviated:
if (abbrev_option) {
/*
@@ -227,7 +228,7 @@ is_abbreviated:
if (!(flags & OPT_UNSET) && *arg_end)
p->opt = arg_end + 1;
abbrev_option = options;
- abbrev_flags = flags;
+ abbrev_flags = flags ^ opt_flags;
continue;
}
/* negation allowed? */
@@ -239,12 +240,18 @@ is_abbreviated:
goto is_abbreviated;
}
/* negated? */
- if (strncmp(arg, "no-", 3))
+ if (prefixcmp(arg, "no-")) {
+ if (!prefixcmp(long_name, "no-")) {
+ long_name += 3;
+ opt_flags |= OPT_UNSET;
+ goto again;
+ }
continue;
+ }
flags |= OPT_UNSET;
- rest = skip_prefix(arg + 3, options->long_name);
+ rest = skip_prefix(arg + 3, long_name);
/* abbreviated and negated? */
- if (!rest && !prefixcmp(options->long_name, arg + 3))
+ if (!rest && !prefixcmp(long_name, arg + 3))
goto is_abbreviated;
if (!rest)
continue;
@@ -254,7 +261,7 @@ is_abbreviated:
continue;
p->opt = rest + 1;
}
- return get_value(p, options, flags);
+ return get_value(p, options, flags ^ opt_flags);
}
if (ambiguous_option)
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 79aefe2..aa57299 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -107,7 +107,7 @@ test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
-test_expect_failure 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
+test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
cat > expect << EOF
boolean: 2
--
1.7.9.2
^ permalink raw reply related
* Re: send-email SMTP/TLS Debugging
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-25 17:55 UTC (permalink / raw)
To: David A. Greene; +Cc: git
In-Reply-To: <874nufv4ov.fsf@smith.obbligato.org>
On 02/25/2012 06:54 AM, David A. Greene wrote:
> Is there some way to turn on TLS authentication debugging using
> git-send-mail? I'm trying to send a patch but git (or the mail server,
> I suppose) keeps telling me I have "Incorrect authentication data."
> I've checked the settings in .git/config multiple times and they look
> correct. How can I debug this further?
Please try 'git send-email --smtp-debug=1 ...'
Zbyszek
^ permalink raw reply
* Re: [PATCH] grep -P: Fix matching ^ and $
From: Zbigniew Jędrzejewski-Szmek @ 2012-02-25 17:52 UTC (permalink / raw)
To: git; +Cc: Michał Kiedrowicz
In-Reply-To: <20120225103050.14f52a91@gmail.com>
On 02/25/2012 10:30 AM, Michał Kiedrowicz wrote:
> Michał Kiedrowicz<michal.kiedrowicz@gmail.com> wrote:
>
>> When `git-grep` is run with -P/--perl-regexp, it doesn't match ^ and $ at
>> the beginning/end of the line. This is because PCRE normally matches ^
>> and $ at the beginning/end of the whole text, not for each line, and git-grep
>> firstly passes a large chunk of text (possibly containing many lines) to
>> pcre_exec() before it splits the text into lines. This makes `git-grep -P`
>> behave differently from `git-grep -E` and also from `grep -P` and `pcregrep`:
Thanks! I can confirm that I now get the expected output.
Zbyszek
> Original report:
> http://permalink.gmane.org/gmane.comp.version-control.git/190830
^ permalink raw reply
* [PATCH] am: don't infloop for an empty input file
From: Jim Meyering @ 2012-02-25 17:34 UTC (permalink / raw)
To: git list
Today, "git am" surprised me.
I mistakenly ran it on an empty file and it went into an infinite loop.
: > e && git am e
To fix it, I made a failing bourne shell "read" break out
of the offending loop. Looking through git-am.sh for other
instances, I did find one, but didn't try to address it here.
action=again
while test "$action" = again
do
gettextln "Commit Body is:"
echo "--------------------------"
cat "$dotest/final-commit"
echo "--------------------------"
# TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
# in your translation. The program will only accept English
# input at this point.
gettext "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
may infloop-> read reply
case "$reply" in
In that case (when someone hits ^D in response to that prompt?),
you may want to exit altogether.
In the test addition, I didn't try to handle potentially-inflooping code.
In coreutils tests, it's easy (since it includes the timeout program):
I would just prefix the command with something like "timeout 10", but
the timeout command is not universally available. And besides, the
infloop is supposed to be fixed, now.
Here's a patch for the infloop I triggered:
[Noticed with and tested against master v1.7.9.2-262-gba998d3,
but seems to apply also to maint. ]
-- >8 --
git-am.sh's check_patch_format function would attempt to preview
the patch to guess its format, but would go into an infinite loop
when the patch file happened to be empty. The solution: exit the
loop when "read" fails, not when the line var, "$l1" becomes empty.
Signed-off-by: Jim Meyering <meyering@redhat.com>
---
git-am.sh | 2 +-
t/t4150-am.sh | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/git-am.sh b/git-am.sh
index 64d8e2a..906f91f 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -202,7 +202,7 @@ check_patch_format () {
l1=
while test -z "$l1"
do
- read l1
+ read l1 || break
done
read l2
read l3
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index f1b60b8..6f77fff 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -505,4 +505,14 @@ test_expect_success 'am -q is quiet' '
! test -s output.out
'
+test_expect_success 'am empty-file does not infloop' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ touch empty-file &&
+ test_tick &&
+ { git am empty-file > actual 2>&1 && false || :; } &&
+ echo Patch format detection failed. >expected &&
+ test_cmp expected actual
+'
+
test_done
--
1.7.9.2.263.g9be8b7
^ permalink raw reply related
* sha-1 check in rev-list --verify-objects redundant?
From: Nguyen Thai Ngoc Duy @ 2012-02-25 17:15 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
Hi,
"git rev-list --verify-objects" calls parse_object() on all except
commits. This function in turn does check_sha1_signature() which
rehashes object content to verify the content matches its sha-1
signature. This is an expensive operation. I wonder if this is a
redundant check. --verify-objects is called to verify new packs.
index-pack is also (always?) called on new packs, and index-pack
hashes all object content, saves the hashes as signature in pack index
file. So they must match. Am I missing something here?
--
Duy
^ permalink raw reply
* Re: cvs2git multiple session for repository migration...
From: Michael Haggerty @ 2012-02-25 15:14 UTC (permalink / raw)
To: supadhyay; +Cc: git
In-Reply-To: <1330092524040-7314909.post@n2.nabble.com>
On 02/24/2012 03:08 PM, supadhyay wrote:
> I am migrating my CVS repository to GIt. As I have multiple repository I
> want to start multiple session for cvs2git,but it failed to start. I
> received cvs2svn.lock file error ? Is there any workaround to start multiple
> cvs2git session (which migrate the CVS directory) ??
>
> Thanks in advance...
Didn't I already mention that cvs2git questions should go to the cvs2svn
mailing list?
You can run cvs2git multiple times simultaneously; you just need to
ensure that each one has its own temporary directory. You can do this
either with the --tmpdir=PATH option or by starting the instances in
separate directories.
Michael
--
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
^ permalink raw reply
* Re: git-subtree Ready #2
From: David A. Greene @ 2012-02-25 15:00 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Avery Pennarun, Jeff King, git
In-Reply-To: <7vy5rrfft2.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
>> I'm happy to do either (rebase or filter-branch). Just let me know.
>
> I would understand Avery's "should we filter-branch/rebase, or is it OK
> as-is?", but I do not understand what you mean by "either rebase or
> filter-branch is fine".
Sorry, got mixed up there. I'm not that familiar with filter-branch.
Now I understand you do both. :)
So have we decided to keep the history?
-Dave
^ permalink raw reply
* Re: [PATCH 2/2] index-pack: reduce memory usage when the pack has large blobs
From: Ian Kumlien @ 2012-02-25 13:17 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <CACsJy8C-8dvXpNTU=JpdupSpS8OuqqTpGvDs6s1ASeKdk9d5Dg@mail.gmail.com>
On Sat, Feb 25, 2012 at 08:49:55AM +0700, Nguyen Thai Ngoc Duy wrote:
> 2012/2/24 Ian Kumlien <pomac@vapor.com>:
> > Writing objects: 100% (1425/1425), 56.06 MiB | 4.62 MiB/s, done.
> > Total 1425 (delta 790), reused 1425 (delta 790)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > fatal: Out of memory, malloc failed (tried to allocate 3310214315 bytes)
> > To ../test_data/
> > ! [remote rejected] master -> master (missing necessary objects)
> > ! [remote rejected] origin/HEAD -> origin/HEAD (missing necessary objects)
> > ! [remote rejected] origin/master -> origin/master (missing necessary objects)
> > error: failed to push some refs to '../test_data/'
> >
> > So there are additional code paths to look at... =(
>
> I can't say where that came from. Does this help? (Space damaged, may
> need manual application)
Everything has so far, since i'm using mainline to get the gzip fixes in
;)
Anyway, with:
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index 264e3ae..533081d 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -183,7 +183,8 @@ static void show_object(struct object *obj,
struct rev_list_info *info = cb_data;
finish_object(obj, path, component, cb_data);
- if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
+ if (info->revs->verify_objects && !obj->parsed
+ && obj->type != OBJ_COMMIT && obj->type != OBJ_BLOB)
parse_object(obj->sha1);
show_object_with_name(stdout, obj, path, component);
}
---
I get:
../git/git push --mirror ../test_data/
Counting objects: 1425, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (617/617), done.
Writing objects: 100% (1425/1425), 56.06 MiB | 4.22 MiB/s, done.
Total 1425 (delta 790), reused 1425 (delta 790)
error: index-pack died of signal 11
error: unpack failed: index-pack abnormal exit
To ../test_data/
! [remote rejected] master -> master (n/a (unpacker error))
! [remote rejected] origin/HEAD -> origin/HEAD (n/a (unpacker error))
! [remote rejected] origin/master -> origin/master (n/a (unpacker error))
error: failed to push some refs to '../test_data/'
Which, to me, means that the installed git is now the problem - it can't verify
the pack and say that it's all ok ;)
I'll have to look some more at this on monday, or during the weekend if i get too curious =)
For now, thank $deity that $company i work for allows VPN from Linux machines! It looks
really good, i wonder if there is further tests i should do - any clues?
> --
> Duy
^ permalink raw reply related
* [PATCH v6 11/11] tag: add --column
From: Nguyễn Thái Ngọc Duy @ 2012-02-25 11:41 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1330170078-29353-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 4 ++++
Documentation/git-tag.txt | 9 +++++++++
Makefile | 2 +-
builtin/tag.c | 26 +++++++++++++++++++++++---
t/t7004-tag.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index ebb210c..145336a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -855,6 +855,10 @@ column.status::
Specify whether to output untracked files in `git status` in columns.
See `column.ui` for details.
+column.tag::
+ Specify whether to output tag listing in `git tag` in columns.
+ See `column.ui` for details.
+
commit.status::
A boolean to enable/disable inclusion of status information in the
commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 8d32b9a..e36a7c3 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -13,6 +13,7 @@ SYNOPSIS
<tagname> [<commit> | <object>]
'git tag' -d <tagname>...
'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
+ [--column[=<options>] | --no-column] [<pattern>...]
[<pattern>...]
'git tag' -v <tagname>...
@@ -84,6 +85,14 @@ OPTIONS
using fnmatch(3)). Multiple patterns may be given; if any of
them matches, the tag is shown.
+--column[=<options>]::
+--no-column::
+ Display tag listing in columns. See configuration variable
+ column.tag for option syntax.`--column` and `--no-column`
+ without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable when listing tags without annotation lines.
+
--contains <commit>::
Only list tags which contain the specified commit.
diff --git a/Makefile b/Makefile
index d9c5f00..65fc6b9 100644
--- a/Makefile
+++ b/Makefile
@@ -2168,7 +2168,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
builtin/tar-tree.o archive-tar.o: tar.h
connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o builtin/commit.o column.o help.o pager.o: column.h
+builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
diff --git a/builtin/tag.c b/builtin/tag.c
index fe7e5e5..e99cbff 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -16,6 +16,7 @@
#include "revision.h"
#include "gpg-interface.h"
#include "sha1-array.h"
+#include "column.h"
static const char * const git_tag_usage[] = {
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
@@ -33,6 +34,7 @@ struct tag_filter {
};
static struct sha1_array points_at;
+static unsigned int colopts;
static int match_pattern(const char **patterns, const char *ref)
{
@@ -263,6 +265,8 @@ static int git_tag_config(const char *var, const char *value, void *cb)
int status = git_gpg_config(var, value, cb);
if (status)
return status;
+ if (!prefixcmp(var, "column."))
+ return git_column_config(var, value, "tag", &colopts);
return git_default_config(var, value, cb);
}
@@ -459,6 +463,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_STRING('u', "local-user", &keyid, "key-id",
"use another key to sign the tag"),
OPT__FORCE(&force, "replace the tag if exists"),
+ OPT_COLUMN(0, "column", &colopts, "show tag list in columns"),
OPT_GROUP("Tag listing options"),
{
@@ -495,9 +500,24 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (list + delete + verify > 1)
usage_with_options(git_tag_usage, options);
- if (list)
- return list_tags(argv, lines == -1 ? 0 : lines,
- with_commit);
+ if (list && lines != -1) {
+ if (explicitly_enable_column(colopts))
+ die(_("--column and -n are incompatible"));
+ colopts = 0;
+ }
+ if (list) {
+ int ret;
+ if (colopts & COL_ENABLED) {
+ struct column_options copts;
+ memset(&copts, 0, sizeof(copts));
+ copts.padding = 2;
+ run_column_filter(colopts, &copts);
+ }
+ ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit);
+ if (colopts & COL_ENABLED)
+ stop_column_filter();
+ return ret;
+ }
if (lines != -1)
die(_("-n option is only allowed with -l."));
if (with_commit)
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index f8c247a..5189446 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -263,6 +263,50 @@ test_expect_success 'tag -l can accept multiple patterns' '
test_cmp expect actual
'
+test_expect_success 'listing tags in column' '
+ COLUMNS=40 git tag -l --column=row >actual &&
+ cat >expected <<\EOF &&
+a1 aa1 cba t210 t211
+v0.2.1 v1.0 v1.0.1 v1.1.3
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'listing tags in column with column.*' '
+ git config column.tag row &&
+ git config column.ui dense &&
+ COLUMNS=40 git tag -l >actual &&
+ git config --unset column.ui &&
+ git config --unset column.tag &&
+ cat >expected <<\EOF &&
+a1 aa1 cba t210 t211
+v0.2.1 v1.0 v1.0.1 v1.1.3
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'listing tag with -n --column should fail' '
+ test_must_fail git tag --column -n
+'
+
+test_expect_success 'listing tags -n in column with column.ui ignored' '
+ git config column.ui "row dense" &&
+ COLUMNS=40 git tag -l -n >actual &&
+ git config --unset column.ui &&
+ cat >expected <<\EOF &&
+a1 Foo
+aa1 Foo
+cba Foo
+t210 Foo
+t211 Foo
+v0.2.1 Foo
+v1.0 Foo
+v1.0.1 Foo
+v1.1.3 Foo
+EOF
+ test_cmp expected actual
+'
+
# creating and verifying lightweight tags:
test_expect_success \
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v6 10/11] column: support piping stdout to external git-column process
From: Nguyễn Thái Ngọc Duy @ 2012-02-25 11:41 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1330170078-29353-1-git-send-email-pclouds@gmail.com>
For too complicated output handling, it'd be easier to just spawn
git-column and redirect stdout to it. This patch provides helpers
to do that.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
column.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
column.h | 3 ++
2 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/column.c b/column.c
index 94fd1a1..ecf2d14 100644
--- a/column.c
+++ b/column.c
@@ -2,6 +2,7 @@
#include "column.h"
#include "string-list.h"
#include "parse-options.h"
+#include "run-command.h"
#include "color.h"
#include "utf8.h"
@@ -407,3 +408,71 @@ int parseopt_column_callback(const struct option *opt,
*mode |= COL_ENABLED | COL_ENABLED_SET;
return 0;
}
+
+static int fd_out = -1;
+static struct child_process column_process;
+
+int run_column_filter(int colopts, const struct column_options *opts)
+{
+ const char *av[10];
+ int ret, ac = 0;
+ struct strbuf sb_colopt = STRBUF_INIT;
+ struct strbuf sb_width = STRBUF_INIT;
+ struct strbuf sb_padding = STRBUF_INIT;
+
+ if (fd_out != -1)
+ return -1;
+
+ av[ac++] = "column";
+ strbuf_addf(&sb_colopt, "--rawmode=%d", colopts);
+ av[ac++] = sb_colopt.buf;
+ if (opts->width) {
+ strbuf_addf(&sb_width, "--width=%d", opts->width);
+ av[ac++] = sb_width.buf;
+ }
+ if (opts->indent) {
+ av[ac++] = "--indent";
+ av[ac++] = opts->indent;
+ }
+ if (opts->padding) {
+ strbuf_addf(&sb_padding, "--padding=%d", opts->padding);
+ av[ac++] = sb_padding.buf;
+ }
+ av[ac] = NULL;
+
+ fflush(stdout);
+ memset(&column_process, 0, sizeof(column_process));
+ column_process.in = -1;
+ column_process.out = dup(1);
+ column_process.git_cmd = 1;
+ column_process.argv = av;
+
+ ret = start_command(&column_process);
+
+ strbuf_release(&sb_colopt);
+ strbuf_release(&sb_width);
+ strbuf_release(&sb_padding);
+
+ if (ret)
+ return -2;
+
+ fd_out = dup(1);
+ close(1);
+ dup2(column_process.in, 1);
+ close(column_process.in);
+ return 0;
+}
+
+int stop_column_filter(void)
+{
+ if (fd_out == -1)
+ return -1;
+
+ fflush(stdout);
+ close(1);
+ finish_command(&column_process);
+ dup2(fd_out, 1);
+ close(fd_out);
+ fd_out = -1;
+ return 0;
+}
diff --git a/column.h b/column.h
index 43528da..cb81c8a 100644
--- a/column.h
+++ b/column.h
@@ -34,4 +34,7 @@ struct option;
extern int parseopt_column_callback(const struct option *opt,
const char *arg, int unset);
+extern int run_column_filter(int colopts, const struct column_options *);
+extern int stop_column_filter();
+
#endif
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v6 09/11] status: add --column
From: Nguyễn Thái Ngọc Duy @ 2012-02-25 11:41 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1330170078-29353-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 4 ++++
Documentation/git-status.txt | 7 +++++++
Makefile | 2 +-
builtin/commit.c | 6 ++++++
t/t7508-status.sh | 24 ++++++++++++++++++++++++
wt-status.c | 28 ++++++++++++++++++++++++++--
wt-status.h | 1 +
7 files changed, 69 insertions(+), 3 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index c14db27..ebb210c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -851,6 +851,10 @@ column.branch::
Specify whether to output branch listing in `git branch` in columns.
See `column.ui` for details.
+column.status::
+ Specify whether to output untracked files in `git status` in columns.
+ See `column.ui` for details.
+
commit.status::
A boolean to enable/disable inclusion of status information in the
commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3d51717..2f87207 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -77,6 +77,13 @@ configuration variable documented in linkgit:git-config[1].
Terminate entries with NUL, instead of LF. This implies
the `--porcelain` output format if no other format is given.
+--column[=<options>]::
+--no-column::
+ Display untracked files in columns. See configuration variable
+ column.status for option syntax.`--column` and `--no-column`
+ without options are equivalent to 'always' and 'never'
+ respectively.
+
OUTPUT
------
diff --git a/Makefile b/Makefile
index 320d3f8..d9c5f00 100644
--- a/Makefile
+++ b/Makefile
@@ -2168,7 +2168,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
builtin/tar-tree.o archive-tar.o: tar.h
connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o column.o help.o pager.o: column.h
+builtin/branch.o builtin/commit.o column.o help.o pager.o: column.h
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
diff --git a/builtin/commit.c b/builtin/commit.c
index 3714582..b42b83f 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -27,6 +27,7 @@
#include "quote.h"
#include "submodule.h"
#include "gpg-interface.h"
+#include "column.h"
static const char * const builtin_commit_usage[] = {
"git commit [options] [--] <filepattern>...",
@@ -88,6 +89,7 @@ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int no_post_rewrite, allow_empty_message;
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
static char *sign_commit;
+static unsigned int colopts;
/*
* The default commit message cleanup mode will remove the lines
@@ -1145,6 +1147,8 @@ static int git_status_config(const char *k, const char *v, void *cb)
{
struct wt_status *s = cb;
+ if (!prefixcmp(k, "column."))
+ return git_column_config(k, v, "status", &colopts);
if (!strcmp(k, "status.submodulesummary")) {
int is_bool;
s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
@@ -1210,6 +1214,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
"ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+ OPT_COLUMN(0, "column", &colopts, "list untracked files in columns"),
OPT_END(),
};
@@ -1223,6 +1228,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix,
builtin_status_options,
builtin_status_usage, 0);
+ s.colopts = colopts;
if (null_termination && status_format == STATUS_FORMAT_LONG)
status_format = STATUS_FORMAT_PORCELAIN;
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index fc57b13..8f5cfac 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -59,6 +59,30 @@ test_expect_success 'status (1)' '
test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
'
+test_expect_success 'status --column' '
+ COLUMNS=50 git status --column="column dense" >output &&
+ cat >expect <<\EOF &&
+# On branch master
+# Changes to be committed:
+# (use "git reset HEAD <file>..." to unstage)
+#
+# new file: dir2/added
+#
+# Changes not staged for commit:
+# (use "git add <file>..." to update what will be committed)
+# (use "git checkout -- <file>..." to discard changes in working directory)
+#
+# modified: dir1/modified
+#
+# Untracked files:
+# (use "git add <file>..." to include in what will be committed)
+#
+# dir1/untracked dir2/untracked untracked
+# dir2/modified output
+EOF
+ test_cmp expect output
+'
+
cat >expect <<\EOF
# On branch master
# Changes to be committed:
diff --git a/wt-status.c b/wt-status.c
index 9ffc535..eee059e 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -11,6 +11,7 @@
#include "remote.h"
#include "refs.h"
#include "submodule.h"
+#include "column.h"
static char default_wt_status_colors[][COLOR_MAXLEN] = {
GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
@@ -641,6 +642,8 @@ static void wt_status_print_other(struct wt_status *s,
{
int i;
struct strbuf buf = STRBUF_INIT;
+ static struct string_list output = STRING_LIST_INIT_DUP;
+ struct column_options copts;
if (!l->nr)
return;
@@ -649,12 +652,33 @@ static void wt_status_print_other(struct wt_status *s,
for (i = 0; i < l->nr; i++) {
struct string_list_item *it;
+ const char *path;
it = &(l->items[i]);
+ path = quote_path(it->string, strlen(it->string),
+ &buf, s->prefix);
+ if (s->colopts & COL_ENABLED) {
+ string_list_append(&output, path);
+ continue;
+ }
status_printf(s, color(WT_STATUS_HEADER, s), "\t");
status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
- "%s\n", quote_path(it->string, strlen(it->string),
- &buf, s->prefix));
+ "%s\n", path);
}
+
+ strbuf_release(&buf);
+ if ((s->colopts & COL_ENABLED) == 0)
+ return;
+
+ strbuf_addf(&buf, "%s#\t%s",
+ color(WT_STATUS_HEADER, s),
+ color(WT_STATUS_UNTRACKED, s));
+ memset(&copts, 0, sizeof(copts));
+ copts.padding = 1;
+ copts.indent = buf.buf;
+ if (want_color(s->use_color))
+ copts.nl = GIT_COLOR_RESET "\n";
+ print_columns(&output, s->colopts, &copts);
+ string_list_clear(&output, 0);
strbuf_release(&buf);
}
diff --git a/wt-status.h b/wt-status.h
index 682b4c8..6dd7207 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -56,6 +56,7 @@ struct wt_status {
enum untracked_status_type show_untracked_files;
const char *ignore_submodule_arg;
char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
+ int colopts;
/* These are computed during processing of the individual sections */
int commitable;
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v6 08/11] branch: add --column
From: Nguyễn Thái Ngọc Duy @ 2012-02-25 11:41 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy
In-Reply-To: <1330170078-29353-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/config.txt | 4 ++
Documentation/git-branch.txt | 9 +++++
Makefile | 2 +-
builtin/branch.c | 32 +++++++++++++++--
t/t3200-branch.sh | 77 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 119 insertions(+), 5 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5216598..c14db27 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -847,6 +847,10 @@ column.ui::
+
This option defaults to 'never'.
+column.branch::
+ Specify whether to output branch listing in `git branch` in columns.
+ See `column.ui` for details.
+
commit.status::
A boolean to enable/disable inclusion of status information in the
commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0427e80..ba5cccb 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -10,6 +10,7 @@ SYNOPSIS
[verse]
'git branch' [--color[=<when>] | --no-color] [-r | -a]
[--list] [-v [--abbrev=<length> | --no-abbrev]]
+ [--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (-m | -M) [<oldbranch>] <newbranch>
@@ -107,6 +108,14 @@ OPTIONS
default to color output.
Same as `--color=never`.
+--column[=<options>]::
+--no-column::
+ Display branch listing in columns. See configuration variable
+ column.branch for option syntax.`--column` and `--no-column`
+ without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable in non-verbose mode.
+
-r::
--remotes::
List or delete (if used with -d) the remote-tracking branches.
diff --git a/Makefile b/Makefile
index 0998f0d..320d3f8 100644
--- a/Makefile
+++ b/Makefile
@@ -2168,7 +2168,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
builtin/tar-tree.o archive-tar.o: tar.h
connect.o transport.o url.o http-backend.o: url.h
-column.o help.o pager.o: column.h
+builtin/branch.o column.o help.o pager.o: column.h
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
diff --git a/builtin/branch.c b/builtin/branch.c
index cb17bc3..611cc0e 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -15,6 +15,8 @@
#include "branch.h"
#include "diff.h"
#include "revision.h"
+#include "string-list.h"
+#include "column.h"
static const char * const builtin_branch_usage[] = {
"git branch [options] [-r | -a] [--merged | --no-merged]",
@@ -53,6 +55,9 @@ static enum merge_filter {
} merge_filter;
static unsigned char merge_filter_ref[20];
+static struct string_list output = STRING_LIST_INIT_DUP;
+static unsigned int colopts;
+
static int parse_branch_color_slot(const char *var, int ofs)
{
if (!strcasecmp(var+ofs, "plain"))
@@ -70,6 +75,8 @@ static int parse_branch_color_slot(const char *var, int ofs)
static int git_branch_config(const char *var, const char *value, void *cb)
{
+ if (!prefixcmp(var, "column."))
+ return git_column_config(var, value, "branch", &colopts);
if (!strcmp(var, "color.branch")) {
branch_use_color = git_config_colorbool(var, value);
return 0;
@@ -474,7 +481,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
else if (verbose)
/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
add_verbose_info(&out, item, verbose, abbrev);
- printf("%s\n", out.buf);
+ if (colopts & COL_ENABLED) {
+ assert(!verbose && "--column and --verbose are incompatible");
+ string_list_append(&output, out.buf);
+ } else {
+ printf("%s\n", out.buf);
+ }
strbuf_release(&name);
strbuf_release(&out);
}
@@ -727,6 +739,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
opt_parse_merge_filter, (intptr_t) "HEAD",
},
+ OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
OPT_END(),
};
@@ -749,6 +762,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
}
hashcpy(merge_filter_ref, head_sha1);
+
+ colopts |= COL_ANSI;
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
@@ -760,12 +775,21 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (abbrev == -1)
abbrev = DEFAULT_ABBREV;
+ if (verbose) {
+ if (explicitly_enable_column(colopts))
+ die(_("--column and --verbose are incompatible"));
+ colopts = 0;
+ }
if (delete)
return delete_branches(argc, argv, delete > 1, kinds);
- else if (list)
- return print_ref_list(kinds, detached, verbose, abbrev,
- with_commit, argv);
+ else if (list) {
+ int ret = print_ref_list(kinds, detached, verbose, abbrev,
+ with_commit, argv);
+ print_columns(&output, colopts, NULL);
+ string_list_clear(&output, 0);
+ return ret;
+ }
else if (edit_description) {
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index dd1aceb..c38592a 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -160,6 +160,83 @@ test_expect_success 'git branch --list -d t should fail' '
test_path_is_missing .git/refs/heads/t
'
+test_expect_success 'git branch --column' '
+ COLUMNS=80 git branch --column=column >actual &&
+ cat >expected <<\EOF &&
+ a/b/c bam foo l * master n o/p r
+ abc bar j/k m/m master2 o/o q
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'git branch --column with an extremely long branch name' '
+ long=this/is/a/part/of/long/branch/name &&
+ long=z$long/$long/$long/$long &&
+ test_when_finished "git branch -d $long" &&
+ git branch $long &&
+ COLUMNS=80 git branch --column=column >actual &&
+ cat >expected <<EOF &&
+ a/b/c
+ abc
+ bam
+ bar
+ foo
+ j/k
+ l
+ m/m
+* master
+ master2
+ n
+ o/o
+ o/p
+ q
+ r
+ $long
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'git branch with column.*' '
+ git config column.ui column &&
+ git config column.branch "dense" &&
+ COLUMNS=80 git branch >actual &&
+ git config --unset column.branch &&
+ git config --unset column.ui &&
+ cat >expected <<\EOF &&
+ a/b/c bam foo l * master n o/p r
+ abc bar j/k m/m master2 o/o q
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'git branch --column -v should fail' '
+ test_must_fail git branch --column -v
+'
+
+test_expect_success 'git branch -v with column.ui ignored' '
+ git config column.ui column &&
+ COLUMNS=80 git branch -v | cut -c -10 | sed "s/ *$//" >actual &&
+ git config --unset column.ui &&
+ cat >expected <<\EOF &&
+ a/b/c
+ abc
+ bam
+ bar
+ foo
+ j/k
+ l
+ m/m
+* master
+ master2
+ n
+ o/o
+ o/p
+ q
+ r
+EOF
+ test_cmp expected actual
+'
+
mv .git/config .git/config-saved
test_expect_success 'git branch -m q q2 without config should succeed' '
--
1.7.8.36.g69ee2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox