I'm trying to write a function quickgit that automatically adds, commits, and pushes with the added benefit of the commit message coming from fortune. I have the following script:
function quickgit
git add --all
git commit -m (fortune)
git push
end
Which works except the commit message is "(fortune)" instead of being a message from fortune. How do I make sure that fortune is run and expanded in my fish function?
fish has enough issues with the finer points of getting quoting just right that I'd avoid using it in scripts entirely. (See https://github.com/fish-shell/fish-shell/issues/159)
I was unable to reproduce your exact issue, but ran into ones of my own around multi-line fortunes. (see the referenced bug)
That being said, for your use case you can avoid it entirely with:
function quickgit
git add --all
fortune | git commit -F -
git push
end
Command substitution splits the output of the command on newline boundaries by default. So a multi-line fortune will pass multiple arguments to the git commit -m. That means only the first line will be handled by the -m option and the second thru n'th lines will end up being treated as file names. Try adding set -l IFS to your function to inhibit that splitting. Another approach is to capture the output in a var then interpolate the var:
set -l fortune (/usr/games/fortune)
git commit -m "$fortune"
But note that will replace each newline with a space.
Related
It is a very simple and stupid question,
I am working on 2 tasks and modified 2 sets of files in the code.
Now when I type 'hg ci', it checks in all the files. Can I remove certain files from the checkin i.e. do checking for only one task?
If I remove the files in the 'check in message' will they be removed from the checkin
Thanks for all the answers
This seems like a big flaw, My use case is very simple and general. Most of the time dev are working on various tasks , some are ready , some are not, bug fixes etc.
Now the only simple solution seems to be multiple local repos or clones
Use hg ci <files>... to commit only certain files in your working directory.
If you want to pick file by file you can use the record command. It ships with mercurial, but you have to turn it on if you want to use it by putting: record= in the [extensions] section of your ~/.hgrc.
It goes hunk by hunk, but you can answer for a whole file:
y - record this change
n - skip this change
s - skip remaining changes to this file
f - record remaining changes to this file
d - done, skip remaining changes and files
a - record all changes to all remaining files
q - quit, recording no changes
? - display help
I'll point out that if you're committing some files but not others it's certain that you've not run your test suite on the one change without the other, but maybe that doesn't apply in your case.
This isn't possible with mercurial out of the box. As have been suggested there are several ways of selecting what files you want to commit. To get this function via the commit message template, you would need an extension or a shell script wrapping the commit command. Here's one way to do that:
[alias]
ci = ! hg-partial-commit
hg-partial-commit:
#!/bin/sh
# partial commit
edit=$(mktemp ${TMPDIR:-/tmp}/$(basename $0).XXXXXXXXXXXX)
filelist=$(mktemp ${TMPDIR:-/tmp}/$(basename $0).XXXXXXXXXXXX)
logmessage=$(mktemp ${TMPDIR:-/tmp}/$(basename $0).XXXXXXXXXXXX)
cleanup="rm -f '$edit' '$filelist' '$logmessage'"
trap "$cleanup" 0 1 2 3 15
(
echo user: $(hg debugconfig ui.username)
echo branch: $(hg branch)
hg parents --template 'parent: {rev}:{node|short} {author} {date|isodate}\n'
echo
echo 'Enter commit message. Select files to commit by deleting lines:'
hg status 'set:not unknown()' | sed -e 's/^/#/'
) | sed -e 's/^/HG: /' >"$edit"
${VISUAL:-${EDITOR:-vi}} "$edit"
egrep -v '^HG:' "$edit" >"$logmessage"
egrep '^HG: #' "$edit" | cut -c8- >"$filelist"
hg commit -l "$logmessage" "listfile:$filelist"
$cleanup
The real problem here is the fact that you're doing changes related to different tasks jumbled together. Mercurial has a few ways you can keep things separate.
Task Branches
Suppose you've been working on a task and you've checked in a few times since you last pulled, but things aren't ready to share yet.
o----o----B----o----o----o
Here, B is the revision where you started your changes. What we do is (after making sure our current changes are checked in):
> hg update -r B
<do our work on the other task>
> hg commit
We've now created a new branch with the changes for this task separated from the changes for our original task.
o----o----B----o----o----o
\
----o
We can do this for as many different tasks as we want. The only problem is that sometimes remembering which branch is which can be awkward. This is where features like bookmarks come in useful. A bookmark is a tag which moves forward as commits are made so that it always points at the head of a branch.
Mercurial Queues
MQ adds the ability to work on changes incrementally and move between them by pushing and poping then off a stack (or "Queue" I guess). So if I had a set of uncommitted changes that I needed to split up I'd:
> hg qrecord taska
> hg qrecord taskb
> hg qrecord taskc
I'd use the record extension (or more likely the crecord extension) to select which parts of files I want to select.
If I needed to go back to taska and make some changes:
> hg qpop; hg qpop # pop two off the queue to go back to task a
<Do changes>
> hg qrefresh # update task a with the new changes
When I want to turn the queue into normal changesets:
> hg qpush or hg qpop # get the changes I want converted onto the queue
> hg qfinish -a # converts mq changes to normal changesets
There's other methods too, but that will do for now.
You will unavoidably have to either specify the files that you want to add or the files you want to leave out. If you have a lot of files, as you indicate above, the following steps will simplify the procedure (I'm assuming a UNIX-ish system here, Windows would be slightly different).
First, generate a list of changed files:
hg status -mard -n >/tmp/changedlist.txt
The -mard options will list all files that were modified, added, removed, or delated. The -n option will list them without the status prefix so that all you have is a raw list of files.
Second, edit /tmp/changedlist.txt with your favorite text editor so that it contains only the files you wish to commit.
Third, commit these files:
hg commit `cat /tmp/changedlist.txt`
You will be able to review the files to be committed before actually performing the commit.
Alternatively, you can add more files to a commit incrementally by using
`hg commit --amend file...`
Here, hg commit --amend will not create a new commit, but add the new files to the existing commit. So, you start out with committing just a couple of files, then incrementally adding more until you are done. This still requires you to type all of them in.
For yet another alternative, you can use Mercurial Queues to split a commit in more sophisticated ways, but that's a bit more of an advanced topic.
How can I sync 2 completely separate trees at a given changelist by entering the changelist only once, e.g. giving the same result as
p4 sync //tree1/a/b/c/...#1234 //tree2/d/e/...#1234
which works, but requires entering 1234 twice?
This gives "syntax error near unexpected token `('":
p4 sync (//tree1/a/b/c/... //tree2/d/e/...)#1234
This syncs //tree1/a/b/c/... to head instead:
p4 sync //tree1/a/b/c/... //tree2/d/e/...#1234
The main reason is that I want to make a shell alias but the 1234 part is user-entered, so it must be entered only once. I know I can use a shell script or function but for various reasons, I must use an alias.
From the comments, the (bash, at least) shell syntax of
p4 sync {//tree1/a/b/c/...,//tree2/d/e/...}#1234
should work. For more explanation, see the brace expansion section of the bash reference.
I'm quite sure is something dealing with my Oh-my-zsh configuration, but I can't figure out what it is.
When I use a "#" symbol in my git command (but on everything else too, like 'ls #2' for instance) I get 'bad pattern' error or 'no match found'
I guess is about counting something, but I can't find where to configure it.
I.E.
➜ demo git:(adlist) git push origin adlist#3
zsh: no matches found: adlist#3
or
➜ demo git:(adlist) git push origin #3-adlist
zsh: bad pattern: #3-adlist
Use single quotes:
git push origin 'adlist#3'
git push origin #3-adlist
In zsh # is used for pattern removal. See: http://zsh.sourceforge.net/Guide/zshguide05.html under the heading Standard forms: pattern removal
You can unsetopt EXTENDED_GLOB, and this should stop # being interpreted as a part of a pattern.
If you really want to keep most of the features of EXTENDED_GLOB, but want to disable # being used for patterns, then you can disable -p '#' (you have to single quote the # argument, so that it doesn't get expanded like a pattern). This certainly works in my zsh installation, version 5.7.1, even though it is not documented in zshbuiltins(1).
Open your zshrc file:
vi ~/.zshrc
Add into end of file:
unsetopt INTERACTIVE_COMMENTS
unsetopt BAD_PATTERN
Effect your file:
source ~/.zshrc
Restart your terminal and enjoy it.
is there a command line program that gives recursive word-based diff (on 2 directories)?
diff -u is recursive, but it doesn't do word by word comparison. wdiff and dwdiff does word based diff but there are not built-in options for recursive diff.
I would like to pipe the result to colordiff so a program that generates output that colordiff understands would be especially useful. Any suggestions? Thanks!
CC
Git can do it and output color:
The following often works:
git diff --color-words path1 path2
but in general you may need to do
git diff --no-index --color-words path1 path2
Neither file even needs to be in a git repository!
--no-index is needed if you and the paths are in a git working tree. It can be elided if you or one of the files are outside a git working tree.
Manpage: https://git-scm.com/docs/git-diff/1.8.5 (and later...)
git diff --no-index [--options] [--] […]
This form is to compare the given two paths on the filesystem. You can
omit the --no-index option when running the command in a working tree
controlled by Git and at least one of the paths points outside the
working tree, or when running the command outside a working tree
controlled by Git.
Is there a way to ask Mercurial to read most/all of the commands, options, and arguments that I want to give it from a response file, instead of passing them on the command line?
For instance, instead of this:
hg commit -m "commit message" --INCLUDE file1 --INCLUDE file2 ...
I would create a text file containing
-m "commit message" --INCLUDE file1 --INCLUDE file2 ...
and then ask Mercurial to read it with this (hyphotetical) syntax:
hg commit #responses.txt
The reason I'm asking is that I'm creating a wrapper library for .NET around the Mercurial command line client, and this question on SO got me worried that the length of the command line might be a problem for me at some point: “Resulting command line for hg.exe too long” error in Mercurial.
There isn't a built-in way to do this as far as I know, but I think there is a way you can build what you need.
Use the Mercurial internal API and write your own wrapper script. Rather than trying to get it to read any and all commands and options, it'll be a lot easier to stick to your specific goal (i.e. "commit" and the options you need).
(Note the warnings on the API page. If this wrapper you're building is going to be distributed to other people, look into the licensing issue and have a plan for how to handle future Mercurial upgrades, which may break your wrapper.)
Here's a kludgy workaround...
Create a dummy, empty response file in the repo's .hg directory, for example .hg\response.
In the repo's .hg\hgrc, add the line
%include response
Before doing any repository operations, write the command line options to this response file. Use the [defaults] section to (I know it's deprecated) to specify your options.
[defaults]
commit = -m "This is a commit message" -I file1 -I file2 ...
(According to Microsoft's support, the maximum command line is 8,191 characters on XP and later. Might be useful to know if you even need to use this trick.)