* Re: What to expect after 0.99.8
From: A Large Angry SCM @ 2005-10-03 3:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v7jcvxxrl.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
> As I mentioned in teh 0.99.8 announcement, let's start aiming
> for 1.0, really this time. From now on, brown paper bags,
> bugfixes, portability fixes, usability enhancements including
> documentation updates take precedence over any new features.
> One exception area is probably merge strategy modules -- they
> are like adding new device drivers or adding new filesystem, and
> can come in anytime as long as they do not touch the coreish.
>
>
> The GIT To-Do File
> ==================
>
> The latest copy of this document is found at
>
> http://kernel.org/git/?p=git/git.git;a=blob;hb=todo;f=TODO
If you were to publish the ToDo to the mailing list once a week it might
encourage more of those patches you want to accept.
>
...
>
> * Maybe update tutorial with a toy project that involves two or
> three developers..
This is *important* to have for 1.0.
>
> * Update tutorial to cover setting up repository hooks to do
> common tasks.
This is nice to have for 1.0.
>
> * Accept patches to finish missing docs.
A list of missing, incomplete, and/or wrong docs in the ToDo file would
help focus effort when people (like me) have space cycles.
>
> * Accept patches to talk about "Whoops, it broke. What's
> next?".
This is *important* to have for 1.0.
>
> * Accept patches to make formatted tables in asciidoc to work
> well in both html and man pages (see git-diff(1)).
A Git documentation asciidoc style guide and howto would be _very_
useful. The current Git documentation is not all that consistent. (and I
accept the blame for the docs I wrote)
>
>
> Technical (heavier)
> -------------------
...
>
> * Maybe a pack optimizer.
Huh?
...
>
> * Internally split the project into non-doc and doc parts; add
> an extra root for the doc part and merge from it; move the
> internal doc source to a separate repository, like the +Meta
> repository; experiment if this results in a reasonable
> workflow, and document it in howto form if it does.
I think this is a bad idea. The docs should be part of the project
(repository and head) as the code. Otherwise, they'll become even more
out-of-sync.
>
...
>
> Technical (trivial)
> -------------------
>
...
>
> * 'git merge-projects'?
Huh?
>
> * 'git lost-and-found'? Link dangling commits found by
> fsck-objects under $GIT_DIR/refs/lost-found/. Then
> show-branch or gitk can be used to find any lost commit. [A
> feeler patch sent out. Very underwhelming response X-<.]
The response may have been underwhelming but it's still a good idea.
>
> Do not name it /lost+found/; that would probably confuse
> things that mistake it a mount point (not our code but
> somebody else's).
I the this concern is overblown.
>
...
^ permalink raw reply
* Re: [howto] Kernel hacker's guide to git, updated
From: Linus Torvalds @ 2005-10-03 1:03 UTC (permalink / raw)
To: Horst von Brand
Cc: Dave Jones, Anton Altaparmakov, Jeff Garzik, Git Mailing List
In-Reply-To: <200510010158.j911wiB3005296@inti.inf.utfsm.cl>
[ Sorry about the spam, most of you probably have never cared ]
On Fri, 30 Sep 2005, Horst von Brand wrote:
>
> I'd been trying my hand at the original version. Need to merge my changes
> with yours...
Heh, now that I got into cleaning things up, I've also been actually
fixing things that have long irritated me, but the code was just too messy
for me, and my level of care wasn't high enough to overcome.
I fixed the "outputs binary data in the 128-159 range to the terminal"
yesterday (which would quite possibly corrupt terminal state if trying to
edit binary files), and today I added a "utf-8" mode.
The utf-8 mode is purely about the _terminal_ being in UTF-8. The actual
editor is still very much byte-char based, but now it understands 8-bit
input that comes in UTF8-encoded, and can output things in UTF-8 format.
(Since UTF-8 is basically always used with Unicode, and the 8-bit subset
of Unicode is iso-8859-1 aka Latin1, this is probably _less_ international
than the non-UTF8, but hey, what can I say? If you want more, you'd need
to teach uemacs about actual UTF8 contents).
The new "emacs.rc" will enable utf-8 mode automatically if $LANG contains
the substring "UTF-8", since that _usually_ means that the terminal is in
utf-8 mode. If it's wrong, you can add or delete the mode by hand (just
like any global mode: Meta-X to add, Meta-Ctrl-X to delete).
Basically, it means that you don't have to switch the whole terminal into
latin1 just to use uemacs.
Linus
^ permalink raw reply
* What to expect after 0.99.8
From: Junio C Hamano @ 2005-10-03 0:14 UTC (permalink / raw)
To: git
As I mentioned in teh 0.99.8 announcement, let's start aiming
for 1.0, really this time. From now on, brown paper bags,
bugfixes, portability fixes, usability enhancements including
documentation updates take precedence over any new features.
One exception area is probably merge strategy modules -- they
are like adding new device drivers or adding new filesystem, and
can come in anytime as long as they do not touch the coreish.
The GIT To-Do File
==================
The latest copy of this document is found at
http://kernel.org/git/?p=git/git.git;a=blob;hb=todo;f=TODO
Tool Renames Plan
=================
- In 0.99.8, we still install the backward compatible symbolic
links in $(bindir). These will however be removed before 1.0
happens.
git-ssh-push and git-ssh-pull pair is not going away within
this timeframe, if ever. Each of these old-name commands
continues to invoke its old-name counterpart on the other
end.
What to expect after 0.99.8
===========================
This is written in a form of to-do list for me, so if I say
"accept patch", it means I do not currently plan to do that
myself. People interested in seeing it materialize please take
a hint.
Documentation
-------------
* Accept patches from people who actually have done CVS
migration and update the cvs-migration documentation.
Link the documentation from the main git.txt page.
* Talk about using rsync just once at the beginning when
initializing a remote repository so that local packs do not
need to be expanded. I personally do not think we need tool
support for this (but see below about optimized cloning).
* Maybe update tutorial with a toy project that involves two or
three developers..
* Update tutorial to cover setting up repository hooks to do
common tasks.
* Accept patches to finish missing docs.
* Accept patches to talk about "Whoops, it broke. What's
next?".
* Accept patches to make formatted tables in asciidoc to work
well in both html and man pages (see git-diff(1)).
Technical (heavier)
-------------------
* We might want to optimize cloning with GIT native transport
not to explode the pack, and store it in objects/pack instead.
We would need a tool to generate an idx file out of a pack
file for this. Also this itself may turn out to be a bad
idea, making the set of packs in repositories everybody has
different from each other.
* Git daemon, when deployed at kernel.org, might turn out to be
quite a burden, since it needs to generate customized packs
every time a new request comes in. It may be worthwhile to
precompute some packs for popular sets of heads downloaders
have and serve that, even if that could give more than the
client asks for in some cases. We will know about this soon
enough.
* Libification. There are many places "run once" mentality is
ingrained in the management of basic data structures, which
need to be fixed.
* Maybe a pack optimizer.
* Maybe an Emacs VC backend.
* 'git split-projects'? This requires updated 'git-rev-list' to
skip irrelevant commits.
Message-ID: <Pine.LNX.4.63.0509221617300.23242@iabervon.org>
* Look at libified GNU diff CVS seems to use, or libxdiff.
Technical (milder)
------------------
* Encourage concrete proposals to commit log message templates
we discussed some time ago.
* Accept patches to cause "read-tree -u" delete a directory when
it makes it empty.
* Perhaps accept patches to introduce the concept of "patch flow
expressed as ref mappings" Josef has been advocating about.
* Perhaps accept patches to do undo/redo.
* Perhaps accept patch to optionally allow '--fuzz' in
'git-apply'.
* Allow 'git apply' to accept GNU diff 2.7 output that forgets
to say '\No newline' if both input ends with incomplete
lines.
* Maybe grok PGP signed text/plain in applymbox as well.
* Perhaps a tool to revert a single file to pre-modification
state? People with BK background know this operation as
'clean'. 'git checkout [-f] ent [path...]' was suggested by
Matthias Urlichs which sounds a natural extention to what the
command currently does.
* Enhance "git repack" to not always use --all; this would be
handy if the repository contains wagging heads like "pu" in
git.git repository.
* Internally split the project into non-doc and doc parts; add
an extra root for the doc part and merge from it; move the
internal doc source to a separate repository, like the +Meta
repository; experiment if this results in a reasonable
workflow, and document it in howto form if it does.
* Make rebase restartable; instead of skipping what cannot be
automatically forward ported, leave the conflicts in the work
tree, have the user resolve it, and then restart from where it
left off.
* Output full path in the "git-rev-list --objects" output, not
just the basename, and see the improved clustering results in
better packing [Tried, but did not work out well].
* Updated git-changes-script Jeff Garzik needs [Inquiry for
external spec sent out with a quick hack. Will know if that
is what he needs soon enough].
Technical (trivial)
-------------------
* short SHA1 naming is not enforcing uniqueness. Should fix.
* 'git repack' can be DOSed. Should fix.
* Stop installing the old-name symlinks [POSTPONED].
* 'git merge-projects'?
* 'git lost-and-found'? Link dangling commits found by
fsck-objects under $GIT_DIR/refs/lost-found/. Then
show-branch or gitk can be used to find any lost commit. [A
feeler patch sent out. Very underwhelming response X-<.]
Do not name it /lost+found/; that would probably confuse
things that mistake it a mount point (not our code but
somebody else's).
* Add simple globbing rules to git-show-branch so that I can
say 'git show-branch --heads "ko-*"' (ko-master, ko-pu, and
ko-rc are in refs/tags/).
* We would want test scripts for the relative directory path
stuff Linus has been working on. So far, the following
commands should be usable with relative directory paths:
git-update-index
git-ls-files
git-diff-files
git-diff-index
git-diff-tree
git-rev-list
git-rev-parse
* In a freashly created empty repository, `git fetch foo:bar`
works OK, but `git checkout bar` afterwards does not (missing
`.git/HEAD`).
\f
Local Variables:
mode: text
End:
^ permalink raw reply
* GIT 0.99.8
From: Junio C Hamano @ 2005-10-03 0:12 UTC (permalink / raw)
To: git
Here is 0.99.8. GIT has been doing everything I personally
wanted it to do since mid 0.99.7, and now it has almost
everything I want it to contain, except for a couple of minor
points. I feel that we are ready to finish the last mile for
1.0. Many thanks to everybody who contributed the comments,
eyeballs, and code.
Done in 0.99.8
==============
New Features, Commands, and Enhancements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* 'git pull' now uses 'git-merge' instead of 'git-resolve', so you can
specify alternative merge strategy to use on its command line.
* 'git pull -s recursive' has been taught about renaming merges,
which may deal with HPA's klibc vs klibc-kbuild situation better.
* Symbolic refs -- instead of using symlinks to express .git/HEAD,
you can have a regular file that stores a single line
'ref: refs/heads/master' in it.
git-update-ref is the preferred way to write into .git/HEAD,
not "echo >.git/HEAD". git-symbolic-ref is the preferred way
to check which underlying ref a symbolic ref .git/HEAD refers
to, not "readlink .git/HEAD".
* A couple of new diff options (-l<num> and --name-status).
* Commit walker over http acquired more SSL options.
* 'git clone' checks out the working tree by default.
Fixes
~~~~~
* Removed unused commands (diff-helper, rev-tree, and export).
* Platforms with only Python 2.3 installed can use recursive merge
strategy.
* Octopus documented.
* Merge is more careful noticing potentially ambiguous situation.
* Git pull does not blindly do Octopus when Pull: lines in remotes
file specifies more than one remote branches.
* Commit walker got safer to use after interrupted downloads.
* Commit walker over http can resume partial downloads.
* More portability fixes for BSD and Solaris.
^ permalink raw reply
* Re: [PATCH] Update git-clone documentation
From: Junio C Hamano @ 2005-10-02 22:54 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: Git Mailing List
In-Reply-To: <m1wtkv903i.fsf@ebiederm.dsl.xmission.com>
Thanks.
^ permalink raw reply
* Re: StGit command completions - and Git ones?
From: Horst von Brand @ 2005-10-02 17:37 UTC (permalink / raw)
To: Blaisorblade; +Cc: Catalin Marinas, git
In-Reply-To: <200510021303.44960.blaisorblade@yahoo.it>
Blaisorblade <blaisorblade@yahoo.it> wrote:
> I noticed in your TODO you talk about adding command line completions. I've
> been doing it for my needs, and the thing is still very incomplete, even if
> it's not a "XXX hack hack hack", and I wanted to send this first draft.
Why don't just lay this at the bash-completion people's feet?
--
Dr. Horst H. von Brand User #22616 counter.li.org
Departamento de Informatica Fono: +56 32 654431
Universidad Tecnica Federico Santa Maria +56 32 654239
Casilla 110-V, Valparaiso, Chile Fax: +56 32 797513
^ permalink raw reply
* [PATCH] Update git-clone documentation
From: Eric W. Biederman @ 2005-10-02 19:42 UTC (permalink / raw)
To: Junio C Hamano, Git Mailing List
The documentation for git-clone is behind the actual command.
I have been getting tired of reading the shell script to see
what the arguments are so here is an update of the actual documentation.
Signed-off-by: Eric Biederman <ebiederman@xmission.com>
git-clone.txt | 15 ++++++++++++++-
1 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -9,7 +9,7 @@ git-clone - Clones a repository.
SYNOPSIS
--------
-'git clone' [-l] [-u <upload-pack>] [-q] <repository> <directory>
+'git clone' [-l [-s]] [-q] [-n] [-u <upload-pack>] <repository> <directory>
DESCRIPTION
-----------
@@ -17,6 +17,7 @@ Clones a repository into a newly created
OPTIONS
-------
+--local::
-l::
When the repository to clone from is on a local machine,
this flag bypasses normal "git aware" transport
@@ -25,10 +26,22 @@ OPTIONS
The files under .git/objects/ directory are hardlinked
to save space when possible.
+--shared::
+-s::
+ When the repository to clone is on the local machine,
+ instead of using hard links automatically setup
+ .git/objects/info/alternatives to share the objects
+ with the source repository
+
+--quiet::
-q::
Operate quietly. This flag is passed to "rsync" and
"git-clone-pack" commands when given.
+-n::
+ No checkout of HEAD is performed after the clone is complete.
+
+--upload-pack <upload-pack>::
-u <upload-pack>::
When given, and the repository to clone from is handled
by 'git-clone-pack', '--exec=<upload-pack>' is passed to
^ permalink raw reply
* Re: [ANNOUNCE] Stacked GIT 0.7
From: Catalin Marinas @ 2005-10-02 19:33 UTC (permalink / raw)
To: Ingo Molnar; +Cc: GIT
In-Reply-To: <20051002121059.GA32367@elte.hu>
On 02/10/05, Ingo Molnar <mingo@elte.hu> wrote:
> i'm wondering - have you (or anyone else) done performance comparisons
> of quilt vs. stgit, using the same stack of patches? One of the most
> important features of quilt (for me) is that it's very fast at
> popping/pushing through hundreds of patches.
I've done some basic comparison and I must admit that Quilt is much
faster than StGIT. Popping is done in O(1) and it is equivalent to a
switch between two branches with 'git checkout' (can be less than 2
seconds with warm caches). Pushing without merging required (i.e.
fast-forwarding) is the same as popping.
What's time consuming is pushing when the base of the stack was
changed and merging is required. If the base changes do not involve
file removals/additions, a push operations takes ~1.5s per patch with
warm caches. Most of the time is spent in "git-read-tree -m" (StGIT
doesn't consume resources since it mainly calls GIT tools). If the
base changes involve file removals/additions, it can take considerably
longer since for each file GIT needs to call an external merger. This
could be solved by providing a smarter git-merge-index to deal with
file removals/additions but the time won't be shorter than ~1.5s per
patch.
An optimisation would be to keep the patches in diff format and apply
them but this would mean losing the advantages of the three-way
merging. Another issue is that git-apply doesn't support fuzzy
patches, though I could emulate it using patch. But I'm not sure
that's a good approach since I don't intend to re-write Quilt in
Python. My hope is that git-read-tree will get faster :-).
--
Catalin
^ permalink raw reply
* Re: Empty commit in linux tree
From: Randy.Dunlap @ 2005-10-02 18:49 UTC (permalink / raw)
To: Marco Costalba; +Cc: git
In-Reply-To: <20051002113344.99131.qmail@web26312.mail.ukl.yahoo.com>
On Sun, 2 Oct 2005 04:33:44 -0700 (PDT) Marco Costalba wrote:
> Commit '[PATCH] Fix IXP2000 serial port resource range'
> (69d37960b578be0a69383bd71d06c1fcfb86e8b9)
> in linux tree seems empty (also with gitweb).
>
> Is this correct?
It was noticed and fixed yesterday...
See http://marc.theaimsgroup.com/?l=linux-kernel&m=112814775418942&w=2
---
~Randy
You can't do anything without having to do something else first.
-- Belefant's Law
^ permalink raw reply
* [PATCH] Teach the recursive merge strategy about renames.
From: Fredrik Kuivinen @ 2005-10-02 15:43 UTC (permalink / raw)
To: git; +Cc: junkio
It will now merge cases where a file was renamed in one branch and
modified in the other branch cleanly. We also detect a couple of
conflict cases now that wasn't detected before.
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
---
This patch turned out to be quite large.
I have tested it on all the problematic merge cases that have been
reported on this list, all multiple common ancestor cases in Thomas
Gleixner's historic Linux repository and a number of handcrafted test
cases.
With the patch the recursive merge strategy produces correct result
for all those merge commits (with one possible exception, see below).
With 'correct result' I mean that one of the following cases occur:
1. The merge is clean and the result match the committed tree.
2. The merge is non-clean.
3. The merge is clean and the difference from the committed tree can
be explained. One commit which is in this category is Tony Luck's
merge (<200508232256.j7NMuR1q027892@agluck-lia64.sc.intel.com>).
The possible exception is commit
091cced38d83732ee3212806ef5ea07abbef01fe in the historic repository.
I have still not managed to find out what the correct result should be
in this case. The recursive strategy merges it cleanly and the result
differs from what was actually committed. The resolve strategy
produces a non-clean result.
There are 409 merge commits in the historic repository which has more
than one common ancestor. Of those 409 commits 26 are merged
non-cleanly by the recursive strategy. Everything else, except
091cce..., is merged cleanly and correctly.
With the resolve strategy we get 73 non-clean results and five cases
which are merged cleanly but the result do not match what was
committed.
git-merge-recursive.py | 794 +++++++++++++++++++++++++++++++++++++-----------
1 files changed, 605 insertions(+), 189 deletions(-)
eccd8d673e2401ed2495272204b42173214ae27c
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -7,9 +7,6 @@ from sets import Set
sys.path.append('@@GIT_PYTHON_PATH@@')
from gitMergeCommon import *
-# The actual merge code
-# ---------------------
-
originalIndexFile = os.environ.get('GIT_INDEX_FILE',
os.environ.get('GIT_DIR', '.git') + '/index')
temporaryIndexFile = os.environ.get('GIT_DIR', '.git') + \
@@ -21,11 +18,23 @@ def setupIndex(temporary):
pass
if temporary:
newIndex = temporaryIndexFile
- os.environ
else:
newIndex = originalIndexFile
os.environ['GIT_INDEX_FILE'] = newIndex
+# This is a global variable which is used in a number of places but
+# only written to in the 'merge' function.
+
+# cacheOnly == True => Don't leave any non-stage 0 entries in the cache and
+# don't update the working directory.
+# False => Leave unmerged entries in the cache and update
+# the working directory.
+
+cacheOnly = False
+
+# The entry point to the merge code
+# ---------------------------------
+
def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
'''Merge the commits h1 and h2, return the resulting virtual
commit object and a flag indicating the cleaness of the merge.'''
@@ -35,6 +44,7 @@ def merge(h1, h2, branch1Name, branch2Na
def infoMsg(*args):
sys.stdout.write(' '*callDepth)
printList(args)
+
infoMsg('Merging:')
infoMsg(h1)
infoMsg(h2)
@@ -46,27 +56,27 @@ def merge(h1, h2, branch1Name, branch2Na
infoMsg(x)
sys.stdout.flush()
- Ms = ca[0]
+ mergedCA = ca[0]
for h in ca[1:]:
- [Ms, ignore] = merge(Ms, h,
- 'Temporary shared merge branch 1',
- 'Temporary shared merge branch 2',
- graph, callDepth+1)
- assert(isinstance(Ms, Commit))
+ [mergedCA, dummy] = merge(mergedCA, h,
+ 'Temporary shared merge branch 1',
+ 'Temporary shared merge branch 2',
+ graph, callDepth+1)
+ assert(isinstance(mergedCA, Commit))
+ global cacheOnly
if callDepth == 0:
setupIndex(False)
- cleanCache = False
+ cacheOnly = False
else:
setupIndex(True)
runProgram(['git-read-tree', h1.tree()])
- cleanCache = True
+ cacheOnly = True
- [shaRes, clean] = mergeTrees(h1.tree(), h2.tree(), Ms.tree(),
- branch1Name, branch2Name,
- cleanCache)
+ [shaRes, clean] = mergeTrees(h1.tree(), h2.tree(), mergedCA.tree(),
+ branch1Name, branch2Name)
- if clean or cleanCache:
+ if clean or cacheOnly:
res = Commit(None, [h1, h2], tree=shaRes)
graph.addNode(res)
else:
@@ -89,16 +99,255 @@ def getFilesAndDirs(tree):
return [files, dirs]
+# Those two global variables are used in a number of places but only
+# written to in 'mergeTrees' and 'uniquePath'. They keep track of
+# every file and directory in the two branches that are about to be
+# merged.
+currentFileSet = None
+currentDirectorySet = None
+
+def mergeTrees(head, merge, common, branch1Name, branch2Name):
+ '''Merge the trees 'head' and 'merge' with the common ancestor
+ 'common'. The name of the head branch is 'branch1Name' and the name of
+ the merge branch is 'branch2Name'. Return a tuple (tree, cleanMerge)
+ where tree is the resulting tree and cleanMerge is True iff the
+ merge was clean.'''
+
+ assert(isSha(head) and isSha(merge) and isSha(common))
+
+ if common == merge:
+ print 'Already uptodate!'
+ return [head, True]
+
+ if cacheOnly:
+ updateArg = '-i'
+ else:
+ updateArg = '-u'
+
+ [out, code] = runProgram(['git-read-tree', updateArg, '-m',
+ common, head, merge], returnCode = True)
+ if code != 0:
+ die('git-read-tree:', out)
+
+ [tree, code] = runProgram('git-write-tree', returnCode=True)
+ tree = tree.rstrip()
+ if code != 0:
+ global currentFileSet, currentDirectorySet
+ [currentFileSet, currentDirectorySet] = getFilesAndDirs(head)
+ [filesM, dirsM] = getFilesAndDirs(merge)
+ currentFileSet.union_update(filesM)
+ currentDirectorySet.union_update(dirsM)
+
+ entries = unmergedCacheEntries()
+ renamesHead = getRenames(head, common, head, merge, entries)
+ renamesMerge = getRenames(merge, common, head, merge, entries)
+
+ cleanMerge = processRenames(renamesHead, renamesMerge,
+ branch1Name, branch2Name)
+ for entry in entries:
+ if entry.processed:
+ continue
+ if not processEntry(entry, branch1Name, branch2Name):
+ cleanMerge = False
+
+ if cleanMerge or cacheOnly:
+ tree = runProgram('git-write-tree').rstrip()
+ else:
+ tree = None
+ else:
+ cleanMerge = True
+
+ return [tree, cleanMerge]
+
+# Low level file merging, update and removal
+# ------------------------------------------
+
+def mergeFile(oPath, oSha, oMode, aPath, aSha, aMode, bPath, bSha, bMode,
+ branch1Name, branch2Name):
+
+ merge = False
+ clean = True
+
+ if stat.S_IFMT(aMode) != stat.S_IFMT(bMode):
+ clean = False
+ if stat.S_ISREG(aMode):
+ mode = aMode
+ sha = aSha
+ else:
+ mode = bMode
+ sha = bSha
+ else:
+ if aSha != oSha and bSha != oSha:
+ merge = True
+
+ if aMode == oMode:
+ mode = bMode
+ else:
+ mode = aMode
+
+ if aSha == oSha:
+ sha = bSha
+ elif bSha == oSha:
+ sha = aSha
+ elif stat.S_ISREG(aMode):
+ assert(stat.S_ISREG(bMode))
+
+ orig = runProgram(['git-unpack-file', oSha]).rstrip()
+ src1 = runProgram(['git-unpack-file', aSha]).rstrip()
+ src2 = runProgram(['git-unpack-file', bSha]).rstrip()
+ [out, code] = runProgram(['merge',
+ '-L', branch1Name + '/' + aPath,
+ '-L', 'orig/' + oPath,
+ '-L', branch2Name + '/' + bPath,
+ src1, orig, src2], returnCode=True)
+
+ sha = runProgram(['git-hash-object', '-t', 'blob', '-w',
+ src1]).rstrip()
+
+ os.unlink(orig)
+ os.unlink(src1)
+ os.unlink(src2)
+
+ clean = (code == 0)
+ else:
+ assert(stat.S_ISLNK(aMode) and stat.S_ISLNK(bMode))
+ sha = aSha
+
+ if aSha != bSha:
+ clean = False
+
+ return [sha, mode, clean, merge]
+
+def updateFile(clean, sha, mode, path):
+ updateCache = cacheOnly or clean
+ updateWd = not cacheOnly
+
+ return updateFileExt(sha, mode, path, updateCache, updateWd)
+
+def updateFileExt(sha, mode, path, updateCache, updateWd):
+ if cacheOnly:
+ updateWd = False
+
+ if updateWd:
+ pathComponents = path.split('/')
+ for x in xrange(1, len(pathComponents)):
+ p = '/'.join(pathComponents[0:x])
+
+ try:
+ createDir = not stat.S_ISDIR(os.lstat(p).st_mode)
+ except:
+ createDir = True
+
+ if createDir:
+ try:
+ os.mkdir(p)
+ except OSError, e:
+ die("Couldn't create directory", p, e.strerror)
+
+ prog = ['git-cat-file', 'blob', sha]
+ if stat.S_ISREG(mode):
+ try:
+ os.unlink(path)
+ except OSError:
+ pass
+ if mode & 0100:
+ mode = 0777
+ else:
+ mode = 0666
+ fd = os.open(path, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, mode)
+ proc = subprocess.Popen(prog, stdout=fd)
+ proc.wait()
+ os.close(fd)
+ elif stat.S_ISLNK(mode):
+ linkTarget = runProgram(prog)
+ os.symlink(linkTarget, path)
+ else:
+ assert(False)
+
+ if updateWd and updateCache:
+ runProgram(['git-update-index', '--add', '--', path])
+ elif updateCache:
+ runProgram(['git-update-index', '--add', '--cacheinfo',
+ '0%o' % mode, sha, path])
+
+def removeFile(clean, path):
+ updateCache = cacheOnly or clean
+ updateWd = not cacheOnly
+
+ if updateCache:
+ runProgram(['git-update-index', '--force-remove', '--', path])
+
+ if updateWd:
+ try:
+ os.unlink(path)
+ except OSError, e:
+ if e.errno != errno.ENOENT and e.errno != errno.EISDIR:
+ raise
+
+def uniquePath(path, branch):
+ def fileExists(path):
+ try:
+ os.lstat(path)
+ return True
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ return False
+ else:
+ raise
+
+ newPath = path + '_' + branch
+ suffix = 0
+ while newPath in currentFileSet or \
+ newPath in currentDirectorySet or \
+ fileExists(newPath):
+ suffix += 1
+ newPath = path + '_' + branch + '_' + str(suffix)
+ currentFileSet.add(newPath)
+ return newPath
+
+# Cache entry management
+# ----------------------
+
class CacheEntry:
def __init__(self, path):
class Stage:
def __init__(self):
self.sha1 = None
self.mode = None
+
+ # Used for debugging only
+ def __str__(self):
+ if self.mode != None:
+ m = '0%o' % self.mode
+ else:
+ m = 'None'
+
+ if self.sha1:
+ sha1 = self.sha1
+ else:
+ sha1 = 'None'
+ return 'sha1: ' + sha1 + ' mode: ' + m
- self.stages = [Stage(), Stage(), Stage()]
+ self.stages = [Stage(), Stage(), Stage(), Stage()]
self.path = path
+ self.processed = False
+
+ def __str__(self):
+ return 'path: ' + self.path + ' stages: ' + repr([str(x) for x in self.stages])
+
+class CacheEntryContainer:
+ def __init__(self):
+ self.entries = {}
+
+ def add(self, entry):
+ self.entries[entry.path] = entry
+ def get(self, path):
+ return self.entries.get(path)
+
+ def __iter__(self):
+ return self.entries.itervalues()
+
unmergedRE = re.compile(r'^([0-7]+) ([0-9a-f]{40}) ([1-3])\t(.*)$', re.S)
def unmergedCacheEntries():
'''Create a dictionary mapping file names to CacheEntry
@@ -108,155 +357,340 @@ def unmergedCacheEntries():
lines = runProgram(['git-ls-files', '-z', '--unmerged']).split('\0')
lines.pop()
- res = {}
+ res = CacheEntryContainer()
for l in lines:
m = unmergedRE.match(l)
if m:
mode = int(m.group(1), 8)
sha1 = m.group(2)
- stage = int(m.group(3)) - 1
+ stage = int(m.group(3))
path = m.group(4)
- if res.has_key(path):
- e = res[path]
- else:
+ e = res.get(path)
+ if not e:
e = CacheEntry(path)
- res[path] = e
-
+ res.add(e)
+
e.stages[stage].mode = mode
e.stages[stage].sha1 = sha1
else:
- die('Error: Merge program failed: Unexpected output from', \
+ die('Error: Merge program failed: Unexpected output from',
'git-ls-files:', l)
return res
-def mergeTrees(head, merge, common, branch1Name, branch2Name,
- cleanCache):
- '''Merge the trees 'head' and 'merge' with the common ancestor
- 'common'. The name of the head branch is 'branch1Name' and the name of
- the merge branch is 'branch2Name'. Return a tuple (tree, cleanMerge)
- where tree is the resulting tree and cleanMerge is True iff the
- merge was clean.'''
+lsTreeRE = re.compile(r'^([0-7]+) (\S+) ([0-9a-f]{40})\t(.*)\n$', re.S)
+def getCacheEntry(path, origTree, aTree, bTree):
+ '''Returns a CacheEntry object which doesn't have to correspond to
+ a real cache entry in Git's index.'''
- assert(isSha(head) and isSha(merge) and isSha(common))
+ def parse(out):
+ if out == '':
+ return [None, None]
+ else:
+ m = lsTreeRE.match(out)
+ if not m:
+ die('Unexpected output from git-ls-tree:', out)
+ elif m.group(2) == 'blob':
+ return [m.group(3), int(m.group(1), 8)]
+ else:
+ return [None, None]
- if common == merge:
- print 'Already uptodate!'
- return [head, True]
+ res = CacheEntry(path)
- if cleanCache:
- updateArg = '-i'
+ [oSha, oMode] = parse(runProgram(['git-ls-tree', origTree, '--', path]))
+ [aSha, aMode] = parse(runProgram(['git-ls-tree', aTree, '--', path]))
+ [bSha, bMode] = parse(runProgram(['git-ls-tree', bTree, '--', path]))
+
+ res.stages[1].sha1 = oSha
+ res.stages[1].mode = oMode
+ res.stages[2].sha1 = aSha
+ res.stages[2].mode = aMode
+ res.stages[3].sha1 = bSha
+ res.stages[3].mode = bMode
+
+ return res
+
+# Rename detection and handling
+# -----------------------------
+
+class RenameEntry:
+ def __init__(self,
+ src, srcSha, srcMode, srcCacheEntry,
+ dst, dstSha, dstMode, dstCacheEntry,
+ score):
+ self.srcName = src
+ self.srcSha = srcSha
+ self.srcMode = srcMode
+ self.srcCacheEntry = srcCacheEntry
+ self.dstName = dst
+ self.dstSha = dstSha
+ self.dstMode = dstMode
+ self.dstCacheEntry = dstCacheEntry
+ self.score = score
+
+ self.processed = False
+
+class RenameEntryContainer:
+ def __init__(self):
+ self.entriesSrc = {}
+ self.entriesDst = {}
+
+ def add(self, entry):
+ self.entriesSrc[entry.srcName] = entry
+ self.entriesDst[entry.dstName] = entry
+
+ def getSrc(self, path):
+ return self.entriesSrc.get(path)
+
+ def getDst(self, path):
+ return self.entriesDst.get(path)
+
+ def __iter__(self):
+ return self.entriesSrc.itervalues()
+
+parseDiffRenamesRE = re.compile('^:([0-7]+) ([0-7]+) ([0-9a-f]{40}) ([0-9a-f]{40}) R([0-9]*)$')
+def getRenames(tree, oTree, aTree, bTree, cacheEntries):
+ '''Get information of all renames which occured between 'oTree' and
+ 'tree'. We need the three trees in the merge ('oTree', 'aTree' and
+ 'bTree') to be able to associate the correct cache entries with
+ the rename information. 'tree' is always equal to either aTree or bTree.'''
+
+ assert(tree == aTree or tree == bTree)
+ inp = runProgram(['git-diff-tree', '-M', '--diff-filter=R', '-r',
+ '-z', oTree, tree])
+
+ ret = RenameEntryContainer()
+ try:
+ recs = inp.split("\0")
+ recs.pop() # remove last entry (which is '')
+ it = recs.__iter__()
+ while True:
+ rec = it.next()
+ m = parseDiffRenamesRE.match(rec)
+
+ if not m:
+ die('Unexpected output from git-diff-tree:', rec)
+
+ srcMode = int(m.group(1), 8)
+ dstMode = int(m.group(2), 8)
+ srcSha = m.group(3)
+ dstSha = m.group(4)
+ score = m.group(5)
+ src = it.next()
+ dst = it.next()
+
+ srcCacheEntry = cacheEntries.get(src)
+ if not srcCacheEntry:
+ srcCacheEntry = getCacheEntry(src, oTree, aTree, bTree)
+ cacheEntries.add(srcCacheEntry)
+
+ dstCacheEntry = cacheEntries.get(dst)
+ if not dstCacheEntry:
+ dstCacheEntry = getCacheEntry(dst, oTree, aTree, bTree)
+ cacheEntries.add(dstCacheEntry)
+
+ ret.add(RenameEntry(src, srcSha, srcMode, srcCacheEntry,
+ dst, dstSha, dstMode, dstCacheEntry,
+ score))
+ except StopIteration:
+ pass
+ return ret
+
+def fmtRename(src, dst):
+ srcPath = src.split('/')
+ dstPath = dst.split('/')
+ path = []
+ endIndex = min(len(srcPath), len(dstPath)) - 1
+ for x in range(0, endIndex):
+ if srcPath[x] == dstPath[x]:
+ path.append(srcPath[x])
+ else:
+ endIndex = x
+ break
+
+ if len(path) > 0:
+ return '/'.join(path) + \
+ '/{' + '/'.join(srcPath[endIndex:]) + ' => ' + \
+ '/'.join(dstPath[endIndex:]) + '}'
else:
- updateArg = '-u'
+ return src + ' => ' + dst
- [out, code] = runProgram(['git-read-tree', updateArg, '-m', common, head, merge], returnCode = True)
- if code != 0:
- die('git-read-tree:', out)
+def processRenames(renamesA, renamesB, branchNameA, branchNameB):
+ srcNames = Set()
+ for x in renamesA:
+ srcNames.add(x.srcName)
+ for x in renamesB:
+ srcNames.add(x.srcName)
cleanMerge = True
-
- [tree, code] = runProgram('git-write-tree', returnCode=True)
- tree = tree.rstrip()
- if code != 0:
- [files, dirs] = getFilesAndDirs(head)
- [filesM, dirsM] = getFilesAndDirs(merge)
- files.union_update(filesM)
- dirs.union_update(dirsM)
+ for path in srcNames:
+ if renamesA.getSrc(path):
+ renames1 = renamesA
+ renames2 = renamesB
+ branchName1 = branchNameA
+ branchName2 = branchNameB
+ else:
+ renames1 = renamesB
+ renames2 = renamesA
+ branchName1 = branchNameB
+ branchName2 = branchNameA
- cleanMerge = True
- entries = unmergedCacheEntries()
- for name in entries:
- if not processEntry(entries[name], branch1Name, branch2Name,
- files, dirs, cleanCache):
+ ren1 = renames1.getSrc(path)
+ ren2 = renames2.getSrc(path)
+
+ ren1.dstCacheEntry.processed = True
+ ren1.srcCacheEntry.processed = True
+
+ if ren1.processed:
+ continue
+
+ ren1.processed = True
+ removeFile(True, ren1.srcName)
+ if ren2:
+ # Renamed in 1 and renamed in 2
+ assert(ren1.srcName == ren2.srcName)
+ ren2.dstCacheEntry.processed = True
+ ren2.processed = True
+
+ if ren1.dstName != ren2.dstName:
+ print 'CONFLICT (rename/rename): Rename', \
+ fmtRename(path, ren1.dstName), 'in branch', branchName1, \
+ 'rename', fmtRename(path, ren2.dstName), 'in', branchName2
cleanMerge = False
-
- if cleanMerge or cleanCache:
- tree = runProgram('git-write-tree').rstrip()
- else:
- tree = None
- else:
- cleanMerge = True
- return [tree, cleanMerge]
+ if ren1.dstName in currentDirectorySet:
+ dstName1 = uniquePath(ren1.dstName, branchName1)
+ print ren1.dstName, 'is a directory in', branchName2, \
+ 'adding as', dstName1, 'instead.'
+ removeFile(False, ren1.dstName)
+ else:
+ dstName1 = ren1.dstName
-def processEntry(entry, branch1Name, branch2Name, files, dirs, cleanCache):
- '''Merge one cache entry. 'files' is a Set with the files in both of
- the heads that we are going to merge. 'dirs' contains the
- corresponding data for directories. If 'cleanCache' is True no
- non-zero stages will be left in the cache for the path
- corresponding to the entry 'entry'.'''
-
-# cleanCache == True => Don't leave any non-stage 0 entries in the cache and
-# don't update the working directory
-# False => Leave unmerged entries and update the working directory
-
-# clean == True => non-conflict case
-# False => conflict case
-
-# If cleanCache == False then the cache shouldn't be updated if clean == False
-
- def updateFile(clean, sha, mode, path, onlyWd=False):
- updateCache = not onlyWd and (cleanCache or (not cleanCache and clean))
- updateWd = onlyWd or (not cleanCache and clean)
-
- if updateWd:
- prog = ['git-cat-file', 'blob', sha]
- if stat.S_ISREG(mode):
- try:
- os.unlink(path)
- except OSError:
- pass
- if mode & 0100:
- mode = 0777
+ if ren2.dstName in currentDirectorySet:
+ dstName2 = uniquePath(ren2.dstName, branchName2)
+ print ren2.dstName, 'is a directory in', branchName1, \
+ 'adding as', dstName2, 'instead.'
+ removeFile(False, ren2.dstName)
else:
- mode = 0666
- fd = os.open(path, os.O_WRONLY | os.O_TRUNC | os.O_CREAT, mode)
- proc = subprocess.Popen(prog, stdout=fd)
- proc.wait()
- os.close(fd)
- elif stat.S_ISLNK(mode):
- linkTarget = runProgram(prog)
- os.symlink(linkTarget, path)
+ dstName2 = ren1.dstName
+
+ updateFile(False, ren1.dstSha, ren1.dstMode, dstName1)
+ updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
else:
- assert(False)
+ print 'Renaming', fmtRename(path, ren1.dstName)
+ [resSha, resMode, clean, merge] = \
+ mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
+ ren1.dstName, ren1.dstSha, ren1.dstMode,
+ ren2.dstName, ren2.dstSha, ren2.dstMode,
+ branchName1, branchName2)
+
+ if merge:
+ print 'Auto-merging', ren1.dstName
+
+ if not clean:
+ print 'CONFLICT (content): merge conflict in', ren1.dstName
+ cleanMerge = False
+
+ if not cacheOnly:
+ updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
+ updateCache=True, updateWd=False)
+ updateFile(clean, resSha, resMode, ren1.dstName)
+ else:
+ # Renamed in 1, maybe changed in 2
+ if renamesA == renames1:
+ stage = 3
+ else:
+ stage = 2
+
+ srcShaOtherBranch = ren1.srcCacheEntry.stages[stage].sha1
+ srcModeOtherBranch = ren1.srcCacheEntry.stages[stage].mode
- if updateWd and updateCache:
- runProgram(['git-update-index', '--add', '--', path])
- elif updateCache:
- runProgram(['git-update-index', '--add', '--cacheinfo',
- '0%o' % mode, sha, path])
-
- def removeFile(clean, path):
- if cleanCache or (not cleanCache and clean):
- runProgram(['git-update-index', '--force-remove', '--', path])
+ dstShaOtherBranch = ren1.dstCacheEntry.stages[stage].sha1
+ dstModeOtherBranch = ren1.dstCacheEntry.stages[stage].mode
- if not cleanCache and clean:
- try:
- os.unlink(path)
- except OSError, e:
- if e.errno != errno.ENOENT and e.errno != errno.EISDIR:
- raise
-
- def uniquePath(path, branch):
- newPath = path + '_' + branch
- suffix = 0
- while newPath in files or newPath in dirs:
- suffix += 1
- newPath = path + '_' + branch + '_' + str(suffix)
- files.add(newPath)
- return newPath
+ tryMerge = False
+
+ if ren1.dstName in currentDirectorySet:
+ newPath = uniquePath(ren1.dstName, branchName1)
+ print 'CONFLICT (rename/directory): Rename', \
+ fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,\
+ 'directory', ren1.dstName, 'added in', branchName2
+ print 'Renaming', ren1.srcName, 'to', newPath, 'instead'
+ cleanMerge = False
+ removeFile(False, ren1.dstName)
+ updateFile(False, ren1.dstSha, ren1.dstMode, newPath)
+ elif srcShaOtherBranch == None:
+ print 'CONFLICT (rename/delete): Rename', \
+ fmtRename(ren1.srcName, ren1.dstName), 'in', \
+ branchName1, 'and deleted in', branchName2
+ cleanMerge = False
+ updateFile(False, ren1.dstSha, ren1.dstMode, ren1.dstName)
+ elif dstShaOtherBranch:
+ newPath = uniquePath(ren1.dstName, branchName2)
+ print 'CONFLICT (rename/add): Rename', \
+ fmtRename(ren1.srcName, ren1.dstName), 'in', \
+ branchName1 + '.', ren1.dstName, 'added in', branchName2
+ print 'Adding as', newPath, 'instead'
+ updateFile(False, dstShaOtherBranch, dstModeOtherBranch, newPath)
+ cleanMerge = False
+ tryMerge = True
+ elif renames2.getDst(ren1.dstName):
+ dst2 = renames2.getDst(ren1.dstName)
+ newPath1 = uniquePath(ren1.dstName, branchName1)
+ newPath2 = uniquePath(dst2.dstName, branchName2)
+ print 'CONFLICT (rename/rename): Rename', \
+ fmtRename(ren1.srcName, ren1.dstName), 'in', \
+ branchName1+'. Rename', \
+ fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2
+ print 'Renaming', ren1.srcName, 'to', newPath1, 'and', \
+ dst2.srcName, 'to', newPath2, 'instead'
+ removeFile(False, ren1.dstName)
+ updateFile(False, ren1.dstSha, ren1.dstMode, newPath1)
+ updateFile(False, dst2.dstSha, dst2.dstMode, newPath2)
+ dst2.processed = True
+ cleanMerge = False
+ else:
+ tryMerge = True
+
+ if tryMerge:
+ print 'Renaming', fmtRename(ren1.srcName, ren1.dstName)
+ [resSha, resMode, clean, merge] = \
+ mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
+ ren1.dstName, ren1.dstSha, ren1.dstMode,
+ ren1.srcName, srcShaOtherBranch, srcModeOtherBranch,
+ branchName1, branchName2)
+
+ if merge:
+ print 'Auto-merging', ren1.dstName
+
+ if not clean:
+ print 'CONFLICT (rename/modify): Merge conflict in', ren1.dstName
+ cleanMerge = False
+
+ if not cacheOnly:
+ updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
+ updateCache=True, updateWd=False)
+ updateFile(clean, resSha, resMode, ren1.dstName)
+
+ return cleanMerge
- debug('processing', entry.path, 'clean cache:', cleanCache)
+# Per entry merge function
+# ------------------------
+
+def processEntry(entry, branch1Name, branch2Name):
+ '''Merge one cache entry.'''
+
+ debug('processing', entry.path, 'clean cache:', cacheOnly)
cleanMerge = True
path = entry.path
- oSha = entry.stages[0].sha1
- oMode = entry.stages[0].mode
- aSha = entry.stages[1].sha1
- aMode = entry.stages[1].mode
- bSha = entry.stages[2].sha1
- bMode = entry.stages[2].mode
+ oSha = entry.stages[1].sha1
+ oMode = entry.stages[1].mode
+ aSha = entry.stages[2].sha1
+ aMode = entry.stages[2].mode
+ bSha = entry.stages[3].sha1
+ bMode = entry.stages[3].mode
assert(oSha == None or isSha(oSha))
assert(aSha == None or isSha(aSha))
@@ -275,28 +709,26 @@ def processEntry(entry, branch1Name, bra
(not aSha and bSha == oSha):
# Deleted in both or deleted in one and unchanged in the other
if aSha:
- print 'Removing ' + path
+ print 'Removing', path
removeFile(True, path)
else:
# Deleted in one and changed in the other
cleanMerge = False
if not aSha:
- print 'CONFLICT (del/mod): "' + path + '" deleted in', \
- branch1Name, 'and modified in', branch2Name, \
- '. Version', branch2Name, ' of "' + path + \
- '" left in tree'
+ print 'CONFLICT (delete/modify):', path, 'deleted in', \
+ branch1Name, 'and modified in', branch2Name + '.', \
+ 'Version', branch2Name, 'of', path, 'left in tree.'
mode = bMode
sha = bSha
else:
- print 'CONFLICT (mod/del): "' + path + '" deleted in', \
- branch2Name, 'and modified in', branch1Name + \
- '. Version', branch1Name, 'of "' + path + \
- '" left in tree'
+ print 'CONFLICT (modify/delete):', path, 'deleted in', \
+ branch2Name, 'and modified in', branch1Name + '.', \
+ 'Version', branch1Name, 'of', path, 'left in tree.'
mode = aMode
sha = aSha
updateFile(False, sha, mode, path)
-
+
elif (not oSha and aSha and not bSha) or \
(not oSha and not aSha and bSha):
#
@@ -307,27 +739,26 @@ def processEntry(entry, branch1Name, bra
otherBranch = branch2Name
mode = aMode
sha = aSha
- conf = 'file/dir'
+ conf = 'file/directory'
else:
addBranch = branch2Name
otherBranch = branch1Name
mode = bMode
sha = bSha
- conf = 'dir/file'
+ conf = 'directory/file'
- if path in dirs:
+ if path in currentDirectorySet:
cleanMerge = False
newPath = uniquePath(path, addBranch)
- print 'CONFLICT (' + conf + \
- '): There is a directory with name "' + path + '" in', \
- otherBranch + '. Adding "' + path + '" as "' + newPath + '"'
+ print 'CONFLICT (' + conf + '):', \
+ 'There is a directory with name', path, 'in', \
+ otherBranch + '. Adding', path, 'as', newPath
removeFile(False, path)
- path = newPath
+ updateFile(False, sha, mode, newPath)
else:
- print 'Adding "' + path + '"'
-
- updateFile(True, sha, mode, path)
+ print 'Adding', path
+ updateFile(True, sha, mode, path)
elif not oSha and aSha and bSha:
#
@@ -336,10 +767,9 @@ def processEntry(entry, branch1Name, bra
if aSha == bSha:
if aMode != bMode:
cleanMerge = False
- print 'CONFLICT: File "' + path + \
- '" added identically in both branches,', \
- 'but permissions conflict', '0%o' % aMode, '->', \
- '0%o' % bMode
+ print 'CONFLICT: File', path, \
+ 'added identically in both branches, but permissions', \
+ 'conflict', '0%o' % aMode, '->', '0%o' % bMode
print 'CONFLICT: adding with permission:', '0%o' % aMode
updateFile(False, aSha, aMode, path)
@@ -350,8 +780,9 @@ def processEntry(entry, branch1Name, bra
cleanMerge = False
newPath1 = uniquePath(path, branch1Name)
newPath2 = uniquePath(path, branch2Name)
- print 'CONFLICT (add/add): File "' + path + \
- '" added non-identically in both branches.'
+ print 'CONFLICT (add/add): File', path, \
+ 'added non-identically in both branches. Adding as', \
+ newPath1, 'and', newPath2, 'instead.'
removeFile(False, path)
updateFile(False, aSha, aMode, newPath1)
updateFile(False, bSha, bMode, newPath2)
@@ -360,39 +791,24 @@ def processEntry(entry, branch1Name, bra
#
# case D: Modified in both, but differently.
#
- print 'Auto-merging', path
- orig = runProgram(['git-unpack-file', oSha]).rstrip()
- src1 = runProgram(['git-unpack-file', aSha]).rstrip()
- src2 = runProgram(['git-unpack-file', bSha]).rstrip()
- [out, ret] = runProgram(['merge',
- '-L', branch1Name + '/' + path,
- '-L', 'orig/' + path,
- '-L', branch2Name + '/' + path,
- src1, orig, src2], returnCode=True)
-
- if aMode == oMode:
- mode = bMode
+ print 'Auto-merging', path
+ [sha, mode, clean, dummy] = \
+ mergeFile(path, oSha, oMode,
+ path, aSha, aMode,
+ path, bSha, bMode,
+ branch1Name, branch2Name)
+ if clean:
+ updateFile(True, sha, mode, path)
else:
- mode = aMode
-
- sha = runProgram(['git-hash-object', '-t', 'blob', '-w',
- src1]).rstrip()
-
- if ret != 0:
cleanMerge = False
- print 'CONFLICT (content): Merge conflict in "' + path + '".'
+ print 'CONFLICT (content): Merge conflict in', path
- if cleanCache:
+ if cacheOnly:
updateFile(False, sha, mode, path)
else:
- updateFile(True, aSha, aMode, path)
- updateFile(False, sha, mode, path, True)
- else:
- updateFile(True, sha, mode, path)
-
- os.unlink(orig)
- os.unlink(src1)
- os.unlink(src2)
+ updateFileExt(aSha, aMode, path,
+ updateCache=True, updateWd=False)
+ updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
else:
die("ERROR: Fatal merge failure, shouldn't happen.")
@@ -416,7 +832,7 @@ for nextArg in xrange(1, len(sys.argv)):
try:
h1 = firstBranch = sys.argv[nextArg + 1]
h2 = secondBranch = sys.argv[nextArg + 2]
- except IndexError:
+ except IndexError:
usage()
break
@@ -428,8 +844,8 @@ try:
graph = buildGraph([h1, h2])
- [res, clean] = merge(graph.shaMap[h1], graph.shaMap[h2],
- firstBranch, secondBranch, graph)
+ [dummy, clean] = merge(graph.shaMap[h1], graph.shaMap[h2],
+ firstBranch, secondBranch, graph)
print ''
except:
^ permalink raw reply
* [PATCH] Teach git-ls-files about '--' to denote end of options.
From: Fredrik Kuivinen @ 2005-10-02 15:33 UTC (permalink / raw)
To: git; +Cc: junkio
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
---
Documentation/git-ls-files.txt | 9 ++++++++-
ls-files.c | 5 ++++-
2 files changed, 12 insertions(+), 2 deletions(-)
1d1f81648fe42497daff2e95320698fa22ca6440
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -13,7 +13,7 @@ SYNOPSIS
(-[c|d|o|i|s|u|k|m])\*
[-x <pattern>|--exclude=<pattern>]
[-X <file>|--exclude-from=<file>]
- [--exclude-per-directory=<file>]
+ [--exclude-per-directory=<file>] [--] [<file>]\*
DESCRIPTION
-----------
@@ -77,6 +77,13 @@ OPTIONS
K to be killed
? other
+--::
+ Do not interpret any more arguments as options.
+
+<file>::
+ Files to show. If no files are given all files which match the other
+ specified criteria are shown.
+
Output
------
show files just outputs the filename unless '--stage' is specified in
diff --git a/ls-files.c b/ls-files.c
--- a/ls-files.c
+++ b/ls-files.c
@@ -530,7 +530,7 @@ static void verify_pathspec(void)
static const char ls_files_usage[] =
"git-ls-files [-z] [-t] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
- "[ --exclude-per-directory=<filename> ]";
+ "[ --exclude-per-directory=<filename> ] [--] [<file>]*";
int main(int argc, const char **argv)
{
@@ -544,6 +544,9 @@ int main(int argc, const char **argv)
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
+ if (!strcmp(arg, "--")) {
+ break;
+ }
if (!strcmp(arg, "-z")) {
line_terminator = 0;
continue;
^ permalink raw reply
* Re: [ANNOUNCE] Stacked GIT 0.7
From: Ingo Molnar @ 2005-10-02 12:10 UTC (permalink / raw)
To: Catalin Marinas; +Cc: GIT
In-Reply-To: <1128244627.9740.6.camel@localhost.localdomain>
* Catalin Marinas <catalin.marinas@gmail.com> wrote:
> Stacked GIT 0.7 release is available from
> http://www.procode.org/stgit/
>
> StGIT is a Python application providing similar functionality to Quilt
> (i.e. pushing/popping patches to/from a stack) on top of GIT. These
> operations are performed using GIT commands and the patches are stored
> as GIT commit objects, allowing easy merging of the StGIT patches into
> other repositories using standard GIT functionality.
i'm wondering - have you (or anyone else) done performance comparisons
of quilt vs. stgit, using the same stack of patches? One of the most
important features of quilt (for me) is that it's very fast at
popping/pushing through hundreds of patches.
Ingo
^ permalink raw reply
* Empty commit in linux tree
From: Marco Costalba @ 2005-10-02 11:33 UTC (permalink / raw)
To: git
Commit '[PATCH] Fix IXP2000 serial port resource range'
(69d37960b578be0a69383bd71d06c1fcfb86e8b9)
in linux tree seems empty (also with gitweb).
Is this correct?
Marco
__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005
http://mail.yahoo.com
^ permalink raw reply
* StGit command completions - and Git ones?
From: Blaisorblade @ 2005-10-02 11:03 UTC (permalink / raw)
To: Catalin Marinas, git
[-- Attachment #1: Type: text/plain, Size: 852 bytes --]
I noticed in your TODO you talk about adding command line completions. I've
been doing it for my needs, and the thing is still very incomplete, even if
it's not a "XXX hack hack hack", and I wanted to send this first draft.
Note: I've not tried to add any completion which isn't StGit specific:
a) I didn't need them
b) they should be implemented for git and cogito first
c) not everything is clear. For instance, I think that SHA1 completion is
pretty useless (I never type a SHA1), while only branch and tag completion
is, but maybe other disagree: there's support for it in Cogito, in fact, and
a shortened SHA1 is used as kernel revision.
--
Inform me of my mistakes, so I can keep imitating Homer Simpson's "Doh!".
Paolo Giarrusso, aka Blaisorblade (Skype ID "PaoloGiarrusso", ICQ 215621894)
http://www.user-mode-linux.org/~blaisorblade
[-- Attachment #2: stg-compl --]
[-- Type: text/plain, Size: 2369 bytes --]
_stg ()
{
local cur cmd cmds
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=()
if [ $COMP_CWORD -eq 1 ]; then
cmds=$(stg help|tail +4|awk '{print $1}')
COMPREPLY=( $(compgen -W "${cmds}" -- $cur) )
else
local cmd=${COMP_WORDS[1]}
local prev=${COMP_WORDS[COMP_CWORD-1]}
#if [ $COMP_CWORD -eq 2 -o "$prev" = "-t" -o "$prev" = "--to" -o "$prev" = "-r" ]; then
local patches
#Add -b support - pass "-b branch" to unapplied and applied.
case $cmd in
push)
patches=$(stg unapplied)
;;
pop|mail)
patches=$(stg applied)
;;
diff|id)
patches=$((stg applied; stg unapplied)|while read i; do echo $i/; done)
;;
esac
case $cmd in
push)
if [ "$prev" = "-t" -o "$prev" = "--to" ]; then
if [ "${cur#*:}" != "${cur}" ]; then
COMPREPLY=( $(compgen -W "${patches}" -- ${cur#*:}) )
else
COMPREPLY=( $(compgen -W "${patches}" -- $cur) )
fi
else
cmds="-a --all -n --number -t --to --reverse --undo -h --help"
COMPREPLY=( $(compgen -W "${cmds} ${patches}" -- $cur) )
fi
;;
pop)
if [ "$prev" = "-t" -o "$prev" = "--to" ]; then
COMPREPLY=( $(compgen -W "${patches}" -- $cur) )
else
cmds="-a --all -n --number -t --to -h --help"
COMPREPLY=( $(compgen -W "${cmds}" -- $cur) )
fi
;;
mail)
if [ "$prev" = "-r" -o "$prev" = "--range" ]; then
if [ "${cur#*:}" != "${cur}" ]; then
COMPREPLY=( $(compgen -W "${patches}" -- ${cur#*:}) )
else
COMPREPLY=( $(compgen -W "${patches}" -- $cur) )
fi
else
cmds="-a --all -r --range --to --cc --bcc -v --version \
-t --template -f --first -s --sleep --refid -u --smtp-user \
-p --smtp-password -b --branch -h --help"
COMPREPLY=( $(compgen -o bashdefault -W "${cmds} ${patches}" -- $cur) )
fi
;;
diff)
if [ "$prev" = "-r" ]; then
if [ "${cur#*:}" != "${cur}" ]; then
COMPREPLY=( $(compgen -W "${patches}" -- ${cur#*:}) )
else
COMPREPLY=( $(compgen -W "${patches}" -- $cur) )
fi
else
cmds="-r -s --stat -h --help"
COMPREPLY=( $(compgen -W "${cmds}" -- $cur) )
fi
;;
id)
cmds="-b --branch -h --help"
COMPREPLY=( $(compgen -W "${cmds} ${patches}" -- $cur) )
;;
*)
COMPREPLY=( $(compgen -f -- $cur) )
;;
esac
#else
#COMPREPLY=( $(compgen -f -- $cur) )
#fi
fi
}
complete -o default -F _stg stg
# vi: set ft=sh:
^ permalink raw reply
* [PATCH Cogito] Fix README asciidoc formatting
From: Jonas Fonseca @ 2005-10-02 10:56 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Add empty lines after code blocks to switch back to normal text.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
BTW, what about adding some notatation info for those boxes? It looks
very creative for an introduction document.
commit ca52918a9a6e02e55d878d8f5e68672432940337
tree 60d270e8b45beeee9361b13284ff2eefec746fd6
parent 9356837de630644323c800e2accad2618d7393f9
author Jonas Fonseca <fonseca@diku.dk> Sun, 02 Oct 2005 12:45:03 +0200
committer Jonas Fonseca <fonseca@antimatter.(none)> Sun, 02 Oct 2005 12:45:03 +0200
README | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/README b/README
--- a/README
+++ b/README
@@ -305,11 +305,13 @@ will `cg-clone` do?
+--------+
+--------+
+
First it creates an empty repository
+--------+
$ origin<
+--------+
+
Then it creates an 'origin' head, and will copy all the history from the
remote repository's 'master' head there. So this head exists to reflect
the state of the remote repository. The important point is that it is
@@ -325,6 +327,7 @@ head and possibly push to it.
| master<
$ origin<
+--------+
+
Finally it copied over the 'origin' head to the 'master' head, which will
from now as your current head represent your local development in the
repository.
@@ -337,6 +340,7 @@ will it do?
| master<
$ origin< < < < <
+--------+
+
First, it will populate your 'origin' head with the new commits from the
remote's 'master' head.
@@ -344,6 +348,7 @@ remote's 'master' head.
| master<-M-.
$ origin>---'
+--------+
+
Then, it will merge those new commits to your 'master' head.
Now let's imagine that there is also another head 'unoji' on the other side
--
Jonas Fonseca
^ permalink raw reply
* [PATCH Cogito] cg-diff: add -s option to summarize (diffstat) changes
From: Jonas Fonseca @ 2005-10-02 10:14 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Pipes the diff output through git-apply --stat --summary.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
commit 20282cdd610ecef03c8c97853bc0749ef3ab32b3
tree 6dd04a780217d116c44c1f78c5e831fc40a32df9
parent b41f8cafc556233613412ff3545e3507202b666a
author Jonas Fonseca <fonseca@diku.dk> Thu, 29 Sep 2005 15:09:42 +0200
committer Jonas Fonseca <fonseca@stud1-9.itu.dk> Thu, 29 Sep 2005 15:09:42 +0200
cg-diff | 17 +++++++++++++++--
1 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/cg-diff b/cg-diff
--- a/cg-diff
+++ b/cg-diff
@@ -17,6 +17,11 @@
# Instead of one ID denotes a parent commit to the specified ID
# (which must not be a tree, obviously).
#
+# -s::
+# Summarize the diff by showing a histogram for removed and added
+# lines (similar to the output of diffstat(1)) and information
+# about added and renamed files and mode changes.
+#
# -r FROM_ID[:TO_ID]::
# Specify the revisions to diff using either '-r rev1:rev2' or
# '-r rev1 -r rev2'. If no revision is specified, the current
@@ -41,7 +46,7 @@
# to before invoking $PAGER. It defaults to $LESS concatenated
# with the `R` flag to allow displaying of colorized output.
-USAGE="cg-diff [-c] [-m] [-p] [-r FROM_ID[:TO_ID]] [FILE]..."
+USAGE="cg-diff [-c] [-m] [-s] [-p] [-r FROM_ID[:TO_ID]] [FILE]..."
. ${COGITO_LIB}cg-Xlib || exit 1
@@ -65,7 +70,12 @@ setup_colors()
colorize()
{
- if [ "$opt_color" ]; then
+ if [ "$opt_summary" ]; then
+ # Add an empty line so the diffstat indentation won't
+ # get messed up
+ echo
+ git-apply --summary --stat
+ elif [ "$opt_color" ]; then
gawk '
{ if (/^(diff --git) /)
print "'$coldiffhdr'" $0 "'$coldefault'"
@@ -96,6 +106,7 @@ id2=" "
parent=
opt_color=
mergebase=
+opt_summary=
while optparse; do
if optparse -c; then
@@ -103,6 +114,8 @@ while optparse; do
setup_colors
elif optparse -p; then
parent=1
+ elif optparse -s; then
+ opt_summary=1
elif optparse -r=; then
if echo "$OPTARG" | fgrep -q '..'; then
id2=${OPTARG#*..}
--
Jonas Fonseca
^ permalink raw reply
* [PATCH Cogito] Copyright and document the cg script
From: Jonas Fonseca @ 2005-10-02 10:13 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Some distributions require all programs to be documented with a manpage so
add a small script header and generate cg(1).
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
commit 9356837de630644323c800e2accad2618d7393f9
tree bdd4c673b6086cee5d5b51ecdb8e2968212afcac
parent 5e15803563ef00720541e89ae16a633ac8dfb7d7
author Jonas Fonseca <fonseca@diku.dk> Thu, 29 Sep 2005 15:13:02 +0200
committer Jonas Fonseca <fonseca@stud1-9.itu.dk> Thu, 29 Sep 2005 15:13:02 +0200
Documentation/Makefile | 12 ++++++++----
cg | 24 ++++++++++++++++++++++++
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/Documentation/Makefile b/Documentation/Makefile
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,7 +1,7 @@
CG_IGNORE=$(wildcard ../cg-X* ../cg-*.orig ../cg-*.rej)
-CG_SRC=$(filter-out $(CG_IGNORE), $(wildcard ../cg-*))
+CG_SRC=$(filter-out $(CG_IGNORE), $(wildcard ../cg*))
-MAN1_TXT=$(patsubst ../cg-%,cg-%.txt,$(CG_SRC))
+MAN1_TXT=$(patsubst ../cg%,cg%.txt,$(CG_SRC))
MAN7_TXT=cogito.txt
DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT)) introduction.html
@@ -54,9 +54,9 @@ install-html: html
$(INSTALL) $(DOC_HTML) $(DESTDIR)/$(htmldir)
clean:
- rm -f *.xml *.html *.1 *.7 cg-*.txt cogito.txt
+ rm -f *.xml *.html *.1 *.7 cg*.txt cogito.txt
-.PRECIOUS: cg-%.txt
+.PRECIOUS: cg%.txt
introduction.html: ../README
asciidoc -b xhtml11 -d article -f asciidoc.conf -o $@ $<
@@ -73,5 +73,9 @@ introduction.html: ../README
cogito.txt : make-cogito-asciidoc
./make-cogito-asciidoc > $@
+# It seems that cg%.txt won't match this so use an explicit rule
+cg.txt : ../cg make-cg-asciidoc
+ ./make-cg-asciidoc $< > $@
+
cg-%.txt : ../cg-% make-cg-asciidoc
./make-cg-asciidoc $< > $@
diff --git a/cg b/cg
--- a/cg
+++ b/cg
@@ -1,4 +1,28 @@
#!/usr/bin/env bash
+#
+# Wrapper for running Cogito commands.
+# Copyright (c) Petr Baudis, 2005
+#
+# Takes a variable number of arguments where the first argument should
+# either be a Cogito command or one of the supported options. If no
+# arguments are specified an overview of all the Cogito commands will be
+# shown.
+#
+# Enables all Cogito commands to be accessed as subcommands, for example
+# is:
+#
+# cg help
+# cg-help
+#
+# equivalent.
+#
+# OPTIONS
+# -------
+# --version::
+# Show the version of the Cogito toolkit. Equivalent to the output
+# of `cg-version`.
+
+USAGE="cg [--version | COMMAND [ARGS]...]"
cmd="$1"; shift
case "$cmd" in
--
Jonas Fonseca
^ permalink raw reply
* [PATCH Cogito] Make cg more robust and user friendly
From: Jonas Fonseca @ 2005-10-02 10:13 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Accept -h in addition to --help. Error out on unknown options. Convert to
be a real bash script and slightly simplify the control flow, so we can use
the 'type' builtin command for checking if the requested Cogito command
exists in the PATH.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
commit 5e15803563ef00720541e89ae16a633ac8dfb7d7
tree 90374bdbc77b04bc5bfa4365e291e3603b0a7099
parent 20282cdd610ecef03c8c97853bc0749ef3ab32b3
author Jonas Fonseca <fonseca@diku.dk> Thu, 29 Sep 2005 15:12:02 +0200
committer Jonas Fonseca <fonseca@stud1-9.itu.dk> Thu, 29 Sep 2005 15:12:02 +0200
cg | 17 ++++++++++++-----
1 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/cg b/cg
--- a/cg
+++ b/cg
@@ -1,9 +1,16 @@
-#!/bin/sh
+#!/usr/bin/env bash
-[ x"$1" = "x" ] && exec cg-help
cmd="$1"; shift
-( [ x"$cmd" = x"--help" ] ) && exec cg-help
-( [ x"$cmd" = x"--version" ] ) && exec cg-version
+case "$cmd" in
+-h|--help|"") cmd="help" ;;
+--version) cmd="version" ;;
+-*)
+ echo "cg: unknown option '$cmd' (try 'cg --help' or 'cg --version')" >&2
+ exit 1
+esac
exe="cg-$cmd"
-exec $exe "$@"
+type -P "$exe" >/dev/null && exec "$exe" "$@"
+
+echo "cg: unknown command '$cmd' (try 'cg help')" >&2
+exit 1
--
Jonas Fonseca
^ permalink raw reply
* [PATCH Cogito] Use git-update-ref for updating the HEAD
From: Jonas Fonseca @ 2005-10-02 10:12 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
Conditionally make git-update-ref check the old head. For this to succeed
for the initial commit, cg-init should not touch .git/refs/heads/master,
and the touching seems to be redundant anyway, so remove it.
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
commit b41f8cafc556233613412ff3545e3507202b666a
tree 9e2c5d8d467acc27d7c866c908990d7de44478f9
parent b06f2a707963c8712f7a6bbd4b89bae758bcf92a
author Jonas Fonseca <fonseca@diku.dk> Thu, 29 Sep 2005 15:09:06 +0200
committer Jonas Fonseca <fonseca@stud1-9.itu.dk> Thu, 29 Sep 2005 15:09:06 +0200
cg-Xlib | 2 +-
cg-commit | 2 +-
cg-init | 1 -
3 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/cg-Xlib b/cg-Xlib
--- a/cg-Xlib
+++ b/cg-Xlib
@@ -246,7 +246,7 @@ tree_timewarp()
fi
git-read-tree -m "$branch" || die "$branch: bad commit"
- [ "$no_head_update" ] || echo "$branch" > $_git/HEAD
+ [ "$no_head_update" ] || git-update-ref HEAD "$branch"
# Kill gone files
git-diff-tree -z -r $base $branch | xargs -0 bash -c '
diff --git a/cg-commit b/cg-commit
--- a/cg-commit
+++ b/cg-commit
@@ -420,7 +420,7 @@ fi
if [ "$newhead" ]; then
echo "Committed as $newhead."
- echo $newhead >$_git/HEAD
+ git-update-ref HEAD $newhead $oldhead
[ "$merging" ] && rm $_git/merging $_git/merging-sym $_git/merge-base
rm -f "$_git/commit-ignore"
diff --git a/cg-init b/cg-init
--- a/cg-init
+++ b/cg-init
@@ -48,7 +48,6 @@ done
cleanup_trap "rm -rf $_git"
git-init-db
-touch $_git/refs/heads/master
git-read-tree # Seed the dircache
if ! [ "$no_initial_commit" ]; then
--
Jonas Fonseca
^ permalink raw reply
* Re: Honor extractor's umask in git-tar-tree.
From: Matthias Urlichs @ 2005-10-02 9:55 UTC (permalink / raw)
To: git
In-Reply-To: <433F52DC.5090906@zytor.com>
Hi, H. Peter Anvin wrote:
> I've thought that it would be nice if the files/directories were written
> into the archive with 0666/0777 permissions by default, and then
> extracted with the umask honoured.
The git archive oesn't *have* permissions, just one "execute" bit.
> A special option then could be used
> to add files with special permissions, like files in .ssh, which *have*
> to be g-w or sshd will reject them.
>
I'd include a script in the archive which you'd run afterwards to fix
problems like this. IMHO, in most situations you'll need it anyway
(for instance, to re-start services).
--
Matthias Urlichs | {M:U} IT Design @ m-u-it.de | smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
- -
As I approached the intersection a sign suddenly appeared in a place
where no stop sign had ever appeared before. I was unable to stop in
time to avoid the accident. To avoid hitting the bumper of the car in
front, I struck the pedestrian.
^ permalink raw reply
* [ANNOUNCE] Stacked GIT 0.7
From: Catalin Marinas @ 2005-10-02 9:17 UTC (permalink / raw)
To: GIT
Stacked GIT 0.7 release is available from http://www.procode.org/stgit/
StGIT is a Python application providing similar functionality to Quilt
(i.e. pushing/popping patches to/from a stack) on top of GIT. These
operations are performed using GIT commands and the patches are stored
as GIT commit objects, allowing easy merging of the StGIT patches into
other repositories using standard GIT functionality.
What's new in this release (the full ChangeLog is in the archive):
* Uses the renamed GIT commands (requires GIT >= 0.99.7)
* 'pick' command to cherry-pick a commit object as an StGIT patch
using a three-way merge. It also allows reverse-applying
* 'commit' command to permanently store the applied patches into
the repository
* 'push' can now fast-forward the patches if the base tree object
has not changed
* The configuration file supports the 'editor' field
* '--version' option for the 'mail' command to generate the e-mail
subject in the form '[PATCH version nr/total]'
* '--showpatch' option for 'refresh' to show the patch content
when editing the patch description
* '--branch' option for several commands to work on a given branch
instead of the current one without switching
* the 'pull' command was updated to follow the 'git pull' API
* '--base' option for 'import' to import a diff file on a
different base and perform a three-way merge with the HEAD
afterwards
* Support for the '.gitignore' file
* Several other optimisations
* Bug fixes
Many thanks to Paolo 'Blaisorblade' Giarrusso, Chuck Lever, Pierre
Ossman and Junio C Hamano for contributing patches to this release.
--
Catalin
^ permalink raw reply
* Re: [howto] Kernel hacker's guide to git, updated
From: Junio C Hamano @ 2005-10-02 8:47 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Linux Kernel, git
In-Reply-To: <433D477A.4010009@pobox.com>
Jeff Garzik <jgarzik@pobox.com> writes:
> Junio C Hamano wrote:
>> Jeff Garzik <jgarzik@pobox.com> writes:
>>> 2) What is the easiest way to obtain a list of changes present in
>>> repository B, that are not present in repository A? I used to use
>>> git-changes-script [hacked cg-log script] for this:
I haven't really *read* that script, but I think it is trying to
make a list of commits from both repositories and trying to find
the set that are in one side and not in the other using diff (a
real shell programer probably would have used "comm" for this
kind of task, not "diff"), then doing a handcrafted git-log on
each of them.
Attached is my quick hack, based on your original question,
without really trying to understand what the script is doing, so
I cannot claim it is a rewrite nor even attempting to be
compatible. Please take a look at it and tell me if this is
any close to what you need.
I have a suspition that this might be better done as a natural
extension of git-log, though.
------------
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
. git-sh-setup || die "Not a git archive"
usage () {
echo >&2 "$0 ( -L | -R ) <dir> [<ref>] [<ref>]
-L shows changes in local not in remote.
-R shows changes in remote not in local.
<dir> names the remote repository.
If given no refs, local and remote HEADs are compared.
If given one ref, local HEAD and named remote ref are compared.
If given two refs, the first names a local ref, and the second names
remote ref to be compared.
"
exit 1
}
case "$1" in
-L | -R)
;;
*)
usage ;;
esac
other="$2"
(
unset GIT_DIR GIT_OBJECT_DIRECTORY
cd "$other" && . git-sh-setup ||
die "$other is not a valid git repository."
)
local=${3:-HEAD}
remote=${4:-HEAD}
# Basic validation.
local=$(git-rev-parse --verify "$local^0" 2>/dev/null) ||
die "local ref $local is not valid."
remote=$(GIT_DIR="$other" git-rev-parse --verify "$remote^0" 2>/dev/null) ||
die "remote ref $remote is not valid."
case "$1" in
-L)
list_args="$local ^$remote" ;;
-R)
list_args="^$local $remote" ;;
esac
GAOD="$GIT_ALTERNATE_OBJECT_DIRECTORIES"
GIT_ALTERNATE_OBJECT_DIRECTORIES="$other/.git/objects:$GAOD" \
git-rev-list --pretty $list_args |
LESS=-S ${PAGER:-less}
^ permalink raw reply
* Re: Honor extractor's umask in git-tar-tree.
From: H. Peter Anvin @ 2005-10-02 3:24 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Rene Scharfe, Linus Torvalds
In-Reply-To: <7vk6gx3vkt.fsf_-_@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
> The archive generated with git-tar-tree had 0755 and 0644 mode bits.
> This inconvenienced the extractor with umask 002 by robbing g+w bit
> unconditionally. Just write it out with loose permissions bits and
> let the umask of the extractor do its job.
I've thought that it would be nice if the files/directories were written
into the archive with 0666/0777 permissions by default, and then
extracted with the umask honoured. A special option then could be used
to add files with special permissions, like files in .ssh, which *have*
to be g-w or sshd will reject them.
-hpa
^ permalink raw reply
* Re: [howto] Kernel hacker's guide to git, updated
From: Horst von Brand @ 2005-10-01 1:58 UTC (permalink / raw)
To: Linus Torvalds
Cc: Horst von Brand, Dave Jones, Anton Altaparmakov, Jeff Garzik,
Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0509301709350.3378@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> wrote:
> On Thu, 29 Sep 2005, Linus Torvalds wrote:
> >
> > I put my git repo on
> >
> > kernel.org:/pub/software/editors/uemacs/uemacs.git
>
> Gaah. You guys shamed me into actually trying to clean up the sources a
> bit.
I'd been trying my hand at the original version. Need to merge my changes
with yours...
--
Dr. Horst H. von Brand User #22616 counter.li.org
Departamento de Informatica Fono: +56 32 654431
Universidad Tecnica Federico Santa Maria +56 32 654239
Casilla 110-V, Valparaiso, Chile Fax: +56 32 797513
^ permalink raw reply
* Re-instate index file write optimization
From: Linus Torvalds @ 2005-10-01 20:39 UTC (permalink / raw)
To: Junio C Hamano, Git Mailing List; +Cc: Wolfgang Denk
This makes "git-update-index" avoid the new index file write if it didn't
make any changes to the index.
It still doesn't make things like "git status" be read-only operations in
general, but if the index file doesn't need refreshing, it now will at
least avoid making unnecessary changes.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
This only makes sense after applying my previous patch, since otherwise a
"--refresh" will always end up marking the index dirty anyway.
Also, while I tried to verify that we always mark the index dirty when we
change it, I can't guarantee it. In particular, since we now map the index
file with PROT_READ | PROT_WRITE, somebody can modify the index entries in
place without getting a SIGSEGV.
Originally you couldn't do the modify-in-place, and used to be that you
could depend on the active_cache[] being unmodified only by actually
assigning to the pointer array itself.
I don't think git-update-index writes to the entries directly, though
(git-read-tree does, but it doesn't do the optimization).
diff --git a/update-index.c b/update-index.c
--- a/update-index.c
+++ b/update-index.c
@@ -391,9 +391,11 @@ int main(int argc, const char **argv)
update_one(buf.buf, prefix, prefix_length);
}
}
- if (write_cache(newfd, active_cache, active_nr) ||
- commit_index_file(&cache_file))
- die("Unable to write new cachefile");
+ if (active_cache_changed) {
+ if (write_cache(newfd, active_cache, active_nr) ||
+ commit_index_file(&cache_file))
+ die("Unable to write new cachefile");
+ }
return has_errors ? 1 : 0;
}
^ permalink raw reply
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