Adding other useful info to a git archive filename automagically - bash

Stumbled across this gem: Export all commits into ZIP files or directories whose inital answer met my needs for exporting commits from certain branches (like develop for example) into separate zip files - all done via a simple, yet clever, one-liner:
git rev-list --all --reverse | while read hash; do git archive --format zip --output ../myproject-commit$((i=i+1))-$hash.zip $hash; done
In my version I replaced the --all with --first-parent develop.
What I would like to do now is make the filenames more useful by including the commit date and commit author in the filename. I've Googled around a bit, grokked the git archive documentation, but do not seem to find any other 'parameters' I could use that are readily available like $hash.
I'm guessing I will need to expand the loop and call up the relevant bits individually, save them into bash variables and pass them on to the output option with something like ${author}, unless anyone else knows a cleaner, simpler way to do this, or can point me to documentation or other examples where I could pull the needed info from other parts of git? Thanks in advance for any insights.

Related

Check out git repository that contains invalid filenames in windows [duplicate]

I'm working a shared project using git for version control. I'm on windows while my partner is on Unix.
My partner has named some files with <file1>.txt. When I try to pull these files they are not accepted as the < and > are invalid characters for Windows. This is fine, I don't need to touch the files. However, they are added to my commit as deleted. So, if I push then I'll delete these files which I don't want to do.
I can't use git reset --hard as it finds an invalid path for each of these "deleted" files.
Is there a way to exclude these files from my commits? I've tried adding <file1> to my .git/info/exclude but that didn't work.
You would need to get your partner to change the names to be something that is also valid on Windows. After they have renamed them, what I'd do is this:
Backup any changes that you only have locally (both uncommitted AND committed but not pushed).
Run git reset --hard <commit> where <commit> is any commit from before the files were added.
Run git pull to get all the way to the latest revision (where the files are renamed).
Restore your backed up changes from 1.
This should then get the newer revision where the files aren't named in this, to Windows, illegal way, and they won't be deleted (or ever created) from under git by the OS :)
P.S. I know this is an old question, but I've been getting this issue recently, so hopefully the solution I've arrived at can help others as well.
EDIT:
To avoid this happening again, your partner can add a pre-commit hook that will stop them from committing files with names that would not be allowed on Windows. There's a sample/example often in pre-commit.sample. I've changed the bit a little in the past and end up with something like:
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
echo $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C)
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ !#-)+-.0-9;=#-[]-{}~]\0' | wc -c) != 0
then
cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
  git config hooks.allownonascii true
EOF
exit 1
fi
The '[ !#-)+-.0-9;=#-[]-{}~]\0' bit is the important part that I've changed a little. It defines all the allowed ranges of characters, and the example one only disallows "non-ascii" characters (which is what the comment at the top says), but there are also ascii characters that are not allowed in file names on Windows (such as ? and :).
All the allowed characters are removed, and if there's anything left (wc -c != 0) it errors. It can be a bit difficult to read, as you can't see any of the disallowed characters. It helps if you have a list of the char ranges to look at when reading or editing it.
Ignoring doesn't help if the files are tracked already.
Use Sparse checkout to skip those files.

Output from git log gets lost when piped to file - what am I missing?

I am trying to get some information about some git commits via the command line as part of a larger automated tool I am building. The information I want is available via this git log command:
git log --branches --graph --oneline --parents
which produces this output:
This is great, because this has the hashes and tags that I want, as well as the commit messages. However, when I pipe this to a file, the stuff in the brackets seems to somehow get lost. I'm not too interested in the colour, but I do want just the plain text as I would expect from any *nix-like program.
This is the output I seem to get instead, which omits some of the output I want (eg, the tag information):
I'm not sure how or why this information gets lost when being piped somewhere. I feel like this might be something incredibly simple and obvious.
I experience the same problem whether I do this in Bash on Arch Linux (with the latest version of git) or in the MINGW64 Bash environment in Windows.
Question: How can I completely capture git log's output without losing the information that is being lost when piping to a file?
You need to add the --decorate option to your log command. Set it either as --decorate=short or --decorate=full.
It appears in your config you've probably got log.decorate set to auto, which means that tags and such are displayed (in short form) when writing to the terminal, but not to a pipe or other file.
Similarly there are config values and command options that govern if (and when) color codes are output; so
git log --branches --graph --oneline --parents --decorate=short --color=always
would output the tags and colors even when redirected to a file.
Note that when scripting you should probably include these options on the command line rather than make assumptions about what config values are set. Depending on what you do with the output, log may or may not be the best command to use in scripting anyway, as git commands are somewhat divided into those meant for human consumption vs those mean for scripting.
Your git command:
git log --branches --graph --oneline --parents
does not produce the same output for me that you show in your first example. It does, however, produce output similar to the second example. The ref names in the brackets (branches and tags) are included when you add the --decorate option. (Here's the documentation.)
Note that your git log format can be controlled in your ~/.gitconfig file. For example, the format you've shown in your question looks like it might be achieved with options like this:
git log --decorate --graph --all --format='%C(auto,yellow)%h%C(auto,reset) %C(auto,yellow)%p%C(auto,reset) %C(auto,red)%d%C(auto,reset) %s %C(auto,green)%an%C(auto,reset) (%C(auto,cyan)%ar%C(auto,reset))'
If you are trying to automate things, you can specify a format that is better tuned to your requirements. Check the git documentation for pretty-formats for details. In particular, look for the %C format, and the %C(auto,…​) notation, which causes colour controls to be used only if the command is run from a terminal.
If you always want to generate the colour information regardless of whether you're using git log interactively, you can remove each ocurrence of auto, in the above line (or alias).

How to convert this script into a custom mercurial command?

I have the following script:
#!/bin/bash
if [ $# -ne 2 ]; then
echo -n "$0 - a utility for applying uncommitted changes to a "
echo "remote hg repository locally also"
echo "Usage: $0 user#hostname path/to/repository"
exit -1
fi
user_at_hostname="$1"
remote_path="$2"
ssh "$user_at_hostname" hg -R "$remote_path" diff | hg import --no-commit -
It's not the most glorious piece of code, and I would rather do something more "mercurial" than that, so to speak. Specifically, I was wondering whether I could achieve the same using a mercurial alias / custom command. Can I?
PS - I had also thought about maybe issuing some sort of shelve command on the remote repository instead of just getting a diff, but I don't want to make thing too complicated.
If you just want to convert this script into an hg foo command without changing it, use a shell alias. Just copy the last line and replace the custom variables with $1 and $2.
If you want to make this look more like a "normal" Mercurial workflow, you could start by committing the changes and then pulling them. I imagine that you are avoiding this workflow so that you can change your mind about these modifications without polluting your repository's history with "oops" commits. If that is the case, then you will likely be interested in the Evolve extension. The Evolve extension is intended to provide a safe and reasonably well-behaved system for sharing mutable history. In this way, you can commit a change; share it with another repository; amend, rebase, squash, or otherwise modify the change; and then share the modified changeset with the same repository or a different one. You can also prune changesets from history and share the fact that you pruned them. If this sharing causes problems, such as amending a commit which has descendants, Mercurial will detect those problems and offer a fix (e.g. rebase the descendants onto the new version of the commit) which you can execute automatically with hg evolve. While the extension is still experimental, it does basically work for most simple use cases.
If experimental software isn't of interest to you, you can still flag the repository as non-publishing. This will allow you to use more traditional history-editing machinery such as hg rebase, hg histedit, and hg strip even after you have pushed to the repository. However, revisions which are destroyed in one repository will not automatically vanish from other repositories without the evolve extension. You will have to strip them by hand.
Finally, note that hg push --force does not destroy revisions. It creates new anonymous branches, typically resulting in a messy history, but without actually losing any data. It is different from git in this fashion.

How can I play a sound whenever I commit to Git?

Writing code alone at home can be an isolating experience. There you are, day in day out, quietly making magic with your mind (sarcasm, obv.) only to silently commit the fruits of your labor into the void of your source control repository, appreciated by no one. If only a crowd of children could be retained for the sole purpose of cheering you on every time you complete something.
How can I play a victory sound every time I commit to Git?
Amazingly, Brandon Keepers over at Collective Idea had the same exact same thought. Anyway, here is what my version of his script looks like:
#!/bin/sh
toplevel_path=`git rev-parse --show-toplevel`
afplay -v 0.1 $toplevel_path/.git/hooks/happykids.wav > /dev/null 2>&1 &
I put this in a file called .git/hooks/post-commit.playsound. I then trigger this from the main .git/hooks/post-commit script as follows:
#!/bin/sh
toplevel_path=`git rev-parse --show-toplevel`
$toplevel_path/.git/hooks/post-commit.tweet
$toplevel_path/.git/hooks/post-commit.playsound
Where the post-commit.tweet script is the script from this StackOverflow answer. If you aren’t also tweeting your commit posts, you’ll want to delete that line.
If you want this to work for every single Git repository from now on, add these scripts to your git-core templates. You’ll have to figure out where these are (it’s different for every setup). For my Mac, they’re located here: /opt/local/share/git-core/templates/hooks/post-commit.

Compiling historical information (esp. SLOCs) about a project

I am looking for a tool that will help me to compile a history of certain code metrics for a given project.
The project is stored inside a mercurial repository and has about a hundred revisions. I am looking for something that:
checks out each revision
computes the metrics and stores them somewhere with an identifier of the revision
does the same with the next revisions
For a start, counting SLOCs would be sufficient, but it would also be nice to analyze # of Tests,TestCoverage etc.
I know such things are usually handled by a CI Server, however I am solo on this project and thus haven't bothered to set up a CI Server (I'd like to use TeamCity but I really didn't see the benefit of doing so in the beginnig). If I'd set up my CI Server now, could it handle that?
According to jitter's suggestion I have written a small bash script running inside cygwin using sloccount for counting the source lines. The output was simply dumped to a textfile:
#!/bin/bash
COUNT=0 #startrev
STOPATREV = 98
until [ $COUNT -gt $STOPATREV ]; do
hg update -C -r $COUNT >> sloc.log # update and log
echo "" >> sloc.log # echo a newline
rm -r lib # dont count lib folder
sloccount /thisIsTheSourcePath | print_sum
let COUNT=COUNT+1
done
You could write a e.g. shell script which
checks out first version
run sloccount on it (save output)
check out next version
repeat steps 2-4
Or look into ohloh which seems to have mercurial support by now.
Otherwise I don't know of any SCM statistics tool which supports mercurial. As mercurial is relatively young (since 2005) it might take some time until such "secondary use cases" are supported. (HINT: maybe provide a hgstat library yourself as there are for svn and csv)
If it were me writing software to do that kind of thing, I think I'd dump metrics results for the project into a single file, and revision control that. Then the "historical analysis" tool would have to pull out old versions of just that one file, rather than having to pull out every old copy of the entire repository and rerun all the tests every time.

Resources