What's the easiest way to use the output paths from a git command in a subsequent git command? - linux

I far too frequently use the mouse to do things like this:
/home/me-$ git log --name-status -1
commit a10e63af1f4b1b2c28055fed55d4f2bb3225a541
Author: Me <me#me.com>
Date: Tue Aug 18 13:04:04 2015 -0400
XYZ-376 make ctors public
M x/y/z/Class1.java
M x/y/z/Class2.java
/home/me-$ git checkout -- x/y/z/Class2.java # <-- copy/paste with the mouse
I know that some git commands accept wildcards, and this mitigates this problem somewhat, but I'm wondering if there is a way do specifically reference pathspecs, etc. from previous commands.
How can I run commands like this without using the mouse, and without retyping long paths by hand?

I typically use a subshell ($(<command in subshell here...>)) for this.
For example, sometimes I had many files deleted and I had to git rm every one of them.
There's the command git ls-files --deleted that returns the names of all the missing files. I can combine it with git rm like this:
git rm $(git ls-files --deleted)
This is somewhat a bad example, because (as I discovered later), this operation can be achieved much easier with git add --all. But I think it illustrates the point.
In your case, if you wanted to checkout all files that have been changed in the previous commit, it would be hard to parse the output of git log --name-status, because it contains additional information, but you could use something like git diff HEAD^ --name-only instead.
So:
git checkout $(git diff HEAD^ --name-only)
will do it in your example.
One nice thing that I noticed using the $(...) syntax is that it works both in Bash and in PowerShell.

This'd be the kind of thing you run a shell under emacs for, run all your shells in it and have a command to walk back through the buffer looking for patterns in the output.
For retrieving output from a previous command that you didn't capture inside the shell session, you're going to have to get it from your terminal emulator's buffers somehow. The xterm family has a configurable "copy the whole scrollback buffer" thingy, then xclip -o will print the selection and you can pipe it through an extraction filter.
But it's either capture the output within the session or scrape it from the output buffers afterwards, that's everywhere the data's ever been.

On OS X, "Mouseless Copy" supported by iTerm2 (and probably some other terminal emulators) is a workable solution: https://www.iterm2.com/features.html
search for some portion of the string (⌘F)
expand selection right (tab) or left (shift-tab)
paste selection with (option-enter) or copy/paste in the usual way

Related

find all lines with specific phrase in specific commit

Lets assume I have a commit with a known hash, and the commit touches 1000 files of 5000 files of the project.
Among some of those files there was added the log message LOG_WARNING(...);, lets say 500 times. Which I want to replace by LOG_INFO(...);.
I don't want to replace all LOG_WARNING(...); in the project (lets say it has 10000 of them), just ones, related to the specified commit.
I'm ready to walk over each of 500 lines I have to modify, but I'm trying to avoid walking over 10000 existing log-lines in the codebase.
What is the best way (practice) to do it?
I would do it that way:
git show --name-only <commit> | xargs sed -i 's/LOG_WARNING/LOG_INFO/'
The git command give the filenames part of the commit.
xargs provides these files to sed which replaces the wanted pattern.
What did help to me:
git diff (...) > patchfile -- extract all changes of current commit to a patchfile
edit patchfile -- using any editing tool & script, but in the patchfile I had to deal with only LOG_WARNING of specified commit.
git reset --hard -- to get rid of the commit I'm going to modify
git apply patchfile -- applies "patch", containing exactly my commit, but with replacement I wanted to.
It does the job. And relatively quickly.

alias with bash involving current system time

I have the problem with macOS mojave, but I guess it generalizes to all bash environment. In the .bashrc or .profile, I add one line as:
alias gc="git add .;git commit --message="$(date +"iMac_%D_%T")""
My purpose is to send the current system time as a message when commiting a change by typing gc. However, the system time was read when alias was invoked (here is when I log in the system).
Can anyone help me out? Thank you in advance!
The simpler approach is to make this a shell function and not an alias at all:
gc() {
git add . && git commit --message="$(date +"iMac_%D_%T")" "$#"
}
That said, as a matter of good git hygeine, I strongly advise against doing this; you'll get output files and temporary files you don't want checked in. git commit -a, by not adding new files, is somewhat safer -- though using git add -p to review changes hunk-by-hunk is by far the best practice to avoid mixing unrelated and unwanted changes into your commits.

Access TortoiseSVN update text

When you use Tortoise SVN to update from the repository to your local machine, you get the popup that shows what files were added/updated/etc. I'm looking to get hold of that text programmatically.
Do you know if it's dumped to a temporary file or a log file? Or is there another way to get hold of that text? I can't see anything in the settings that provides for it.
One idea might be to use the svn.exe console program, like this
svn.exe log -r head -v <svn-dir>
-r means the revision (head being the newest)
-v being verbose (which includes the file names)
<svn-dir> is a dir that contains a svn checkout ( this can be omitted if you run the command inside such a dir).
There are also an -xml switch that might be useful if you want to massage the data in some way
This requires that you have a svn.exe in you path. It seems to be possible to find the svn.exe exec. here

Moving a git repo to another server

I have a git clone/repo on a development server, but I am now moving to another one. I don't want to commit all my local branches and changes to the main repository, so how can I make an exact copy of everything on oldserver to newserver?
I tried oldserver:~$ scp -rp project newserver:~/project
but then I just get loads and loads of "typechange" errors when trying to do anything on newserver.
Someone said something about x-modes, but how can I preserve that when moving files between servers?
If you want a git solution, you could try
git clone --mirror <oldurl> <newurl>
though this is only for bare repositories.
If this is a non-bare repo, you could also do the normal clone, followed by something like this:
git fetch origin
git branch -r | grep '^ *origin/[^ ]*$' |
while read rb; do git branch --no-track ${rb#*/} $rb; done
git remote rm origin
The middle step can of course be done in 5000 different ways, but that's one! (note that the continuation line \ isn't necessary after the pipe in bash - it knows it needs more input)
Finally, I'd suggest using rsync instead of scp (probably with -avz options?) if you want to directly copy. (What exactly are these typechange errors?)
I've actually done this, and all I did was tar the repo up first and scp it over. I would think that scp -rp would work as well.
"Typechange" would normally refer to things like a symlink becoming a file or vice-versa. Are the two servers running the same OS?
You may also want to try the simple dumb solution -- don't worry about how the typechanges got there, but let git fix them with a reset command:
git reset --hard HEAD
That only makes sense if (1) the problems all pertain to the checked-out files (and not the repository structure itself) and (2) you haven't made any changes on newserver which you need to preserve.
Given those caveats, it worked for me when I found myself with the same problem, and it doesn't require you to think about git's internals or how well your file-transfer process is preserving attributes.

How to automatically edit commits after "git-rebase -i"?

Very often I need to change the date of n previous commits. Usually I do git rebase -i #~20 and then in the editor manually change pick to edit, after that run in the loop commit --amend with desired date. It all works nicely, but I would like to automate the process so that the editor would not be called at all.
The question is: how do I switch to "edit mode" automatically after git rebase?
You can write a script that will behave like an editor and does what you want(it will be called with a temporary file and should modify it), then run the rebase with it - EDITOR=/path/to/your/script git rebase -i #~20
Also you might want to look onto git filter-branch approach suggested in How can one change the timestamp of an old commit in Git?

Resources