On Tue, 12 Nov 2013 08:11:40 -0800 (PST)
Gabby Romano <omerik...@gmail.com> wrote:
> I would like to be able to prevent case name changes done on windows
> clients and being pushed to our linux remote repository. when pulled,
> it confuses the other windows clients and messes things up. I want to
> use a hook for that along with the rename detection mechanism of git,
> if I can call it this way.
> my question is - what would be the best way to approach this in the
> hook ? detect the rename and check the content is the same (sha1
> check ? )
> am I wrong regarding the approach in general and there is a much
> better way to do this ?
I think it's a viable approach though it should be used somewhat
differently to what you proposed.
Git does not explicitly track file renames so renaming a file (without
changing the file's contents) physically looks like a (new) commit
indirectly referencing *the same* blob of data as does one of its parent
commits, but this blob has a different symbolic name attached to it in
one of the tree objects referenced by both commits.
In Git, each commit references exactly one tree object (representing the
root directory of the project), and that tree object might reference
zero or more other tree objects -- one for each top-level subdirectory,
and so on and so on going deeper down. Tree objects also reference
blobs which contain the data of tracked files. In a tree object, both
references to blobs and to other tree objects are decorated with
"filesystem names" for these objects. That's how filesystem
hierarchies are mapped to Git objects in its database.
As you can see, renames can only be detected by analyzing a part
of the commit graph using special algorythms. Fortunately, Git has
this machinery implemented for you in its `git diff` command:
git diff --name-status --diff-filter=R --find-renames A B
should present you with a list or files (along with the "Rnnn" marker in
front of them) which were renamed in commit B compared to commit A.
"R" means Git detected the file has been renamed, and "nnn" shows you
the persentage of the file's contents which remained unchanged (the
similarity index; 100% means the file's content hasn't changed).
Applying this paradigm in a post-receive hook *might* be more involved
since any push operation might update any ref (a branch or a tag) with
more than one commit at once -- in a general case with a graph of
commits. If you're fine with merely making sure the new tip commit
does not introduce any rename compared to the old one, ignoring
anything which might have happened in between, just use `git diff` as
shown above. If, instead, you want to be sure no commit between A and B
introduced a rename, you should employ the fact the command for walking
commit graphs, `git log`, is able to use `git diff` machinery for
analyzing the commits as it walks.
Hence, if we have a ref that is currently pointing to a commit A, and
it's about to be updated by the push operation to point to a commit B,
we could call
git log --oneline --name-status --diff-filter=R --find-renames A..B
to list all commits sent to update our ref, which contain renames.
Notice that `git diff` is passed the two revisions as a separate
arguments, and `git log` receives the rule "A..B" which means "all
commits reachable from B excluding all commits reachable from A".
I should stress again that there are no renames in Git -- in this VCS
this concept is purely synthetic, and so there are knobs to control the
algorythm which detects renames. At least you can specify which
persentage of the file contents must be *not* changed in a commit to
count as a rename. The rationale: in a given commit, a file might be
both changed and renamed, and since their contents differ, how do you
tell if it's still logically the same file or not? You might tell Git
your idea about this -- read the `git diff` manual page about the
"--find-renames" ("-M") command-line option.
You received this message because you are subscribed to the Google Groups "Git
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email
For more options, visit https://groups.google.com/groups/opt_out.