Split top commit in half
More at source: On undoing, fixing, or removing commits in git - A git choose-your-own-adventure!ⓡ
See also Post-Production Editing Using Git for great tutorial on git rebase -i $EARLIER_SHA
$ git reset HEAD^
$ git add -p
WARNING: These techniques should only be used for non-merge commits. If you have a merge commit, you are better off deleting the merge and recreating it.
If you want to perform significant work on the last commit, you can simply
git reset HEAD^
. This will undo the commit (peel it off) and restore the index to the state it was in before that commit, leaving the working directory with the changes uncommitted, and you can fix whatever you need to fix and try again.[…]
Transplant a patch from unrelated repository
Source: http://stackoverflow.com/a/9507417/98528
Single commit/patch
$ git --git-dir=../source_repo/.git \
format-patch -k -1 --stdout \
$COMMIT_SINCE | \
git am -3 -k --committer-date-is-author-date
where format-patch
options are:
-k, --keep-subject
Do not strip/add [PATCH] from the first line of the commit log message.-1, -<n>
Prepare patches from the topmostcommits. --stdout
Print all commits to the standard output in mbox format, instead of creating a file for each one.
Multiple commits
Assuming a repository like:
[A] -> [B] -> [C] -> [D] -> [E] ...
You can transplant it onto unrelated repository [X]
, to achieve something like:
[X] -> [C] -> [D] -> [E] ...
To do that, first, git fetch
both repositories into one, then:
git rebase B E --onto X --committer-date-is-author-date
Source: http://stackoverflow.com/a/9091843/98528
Apply patch in fuzzy way
[TODO]
See: git help apply
git apply [OPTIONS] [<patch>...]
--recount
— tries to apply changes in fuzzy way--index
— puts the changes into staged area too
Does not create a commit.
Show history using pretty ASCII-Art tree graph
Simpler variant, possible to quickly type by hand from memory
$ git log --graph --oneline --decorate --all "$@"
(old version: git log --graph --decorate --pretty=oneline --abbrev-commit --all "$@"
)
Better variant, impossible to type quickly from memory, paste it into a script
$ git log --graph --all --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(cyan)%an%Creset' --abbrev-commit
Remove local changes
More at source: How to revert all local changes in a GIT managed project to previous state?
If you want to revert changes made to your working copy, do this:
git checkout .
If you want to revert changes made to the index (i.e., that you have added), do this:
git reset
Merge, ignoring whitespace
Source: http://stackoverflow.com/a/9784089/98528
git merge -Xignore-space-change
Merge a related snapshot repo
To create a merge like in diagram below:
o merge!
|\
| o [snapshot]
o [old]
|
o
|
o rev0
where “snapshot” is newer than “old”, do as follows:
git checkout old
git merge -ssubtree snapshot -Xignore-space-change
3-way diff of a file during merge/rebase
Sources: Git Conflict Resolution, man git
git -c merge.conflictstyle=diff3 checkout -m $FILE
Search repo/history
a) Find commits which add/remove lines matching a regex (i.e. search history)
git log -G"$REGEX" -p --decorate -a
-p
shows the actual diff, only of the files containing the change (I think)--decorate
is optional (shows info about tags, branches etc.)-a
I think makes it look into all commits on all branches. I don’t know yet how to sort the results in sensible order (e.g. by date), however.- alternatively, instead of
-G
, can use-S
for simple strings, but it has slightly different semantics! It shows commits where the total count of lines matching the string changes.
b) Find text in current repository
In other words, a “faster grep
“:
git grep ...
Bonus: can be set as :grep
in vim with:
:set gp=git\ grep\ -n
c) Find commit by date
git rev-list -n 1 --before="2009-07-27 13:37" master
Source: stackoverflow
Partial (“sparse”) checkouts
Git 1.7+
Initial setup, Linux [1][2]
(unverified yet)
The .git/info/sparse-checkout
file uses patterns “similar to .gitignore” [2][3]
git config core.sparsecheckout true
git remote add -f origin git://...
## NOTE: below no whitespace between '*' and '>'
#echo PATH/TO/SUBDIR/*> .git/info/sparse-checkout
echo some/dir/ >> .git/info/sparse-checkout
echo another/sub/tree >> .git/info/sparse-checkout
git checkout BRANCHNAME
Existing repo, or changes [1]
git config core.sparsecheckout true
echo some/dir/ >> .git/info/sparse-checkout
echo another/sub/tree >> .git/info/sparse-checkout
git read-tree -mu HEAD
Disable [1]
(unverified)
echo '*' > .git/info/sparse-checkout
git read-tree -mu HEAD
git config core.sparsecheckout false
Retrieve a file from specific revision
Sources: stackoverflow
git show $REV:$PATH
Since git ~1.7+, $PATH
can be relative with ./path
.
Alternatively, if the file is to be restored at its original place, a shortcut is:
git checkout $REV $PATH
Source: http://stackoverflow.com/a/2734035
Browse deleted files per commit
Source: stackoverflow
git log --diff-filter=D --summary
List all files in repo
git ls-tree --full-tree -r HEAD
— list all tracked files already in repo (via);git ls-files
— list files including staged (via);
commit: show full diff in editor
Source: stackoverflow
git commit --verbose
log/diff: file names only
Source: stackoverflow
git log --pretty="format:" --name-only [RANGE...]
Git attic: list deleted files
#!/bin/sh
# git-attic [-M] [PATH] - list deleted files of Git repositories
#
# Use -M to not show renamed files, and other git-log options as you like.
git log --raw --no-renames --date=short --format="%h %cd" "$@" |
awk '/^[0-9a-f]/ { commit=$1; date=$2 }
/^:/ && $5 == "D" { print date, commit "^:" $6 }' |
git -p column
Source: http://chneukirchen.org/blog/archive/2013/01/a-grab-bag-of-git-tricks.html
Git submodule from existing .git subdir
ORIGIN_URL=$( git --git-dir $SUBREPO/.git config --get remote.origin.url | tee /dev/stderr )
git submodule add $ORIGIN_URL $SUBREPO
Sources: man git-submodule, remote.origin.url
Ways to specify a commit
Commit:
HEAD^
— commit before HEADHEAD^2
— chooses other parent in merge commitsHEAD^^
,HEAD^^^
, … — grandparent of HEAD, grand-grandparent, etc.
HEAD~3
=HEAD^^^
=HEAD^1^1^1
:/"commit message regexp"
— newest commit with regexp match in commit message, reachable from anywherev0.1^{/"commit message regexp"}
— newest commit with regexp, reachable from v0.1
refs/heads/master
,refs/tags/v0.1
— “fully qualified” names of: branch master, tag v0.1
(See: git help revisions)
Range of commits:
HEAD^!
≟HEAD^..HEAD
Gerrit
Fetch all reviews of a particular change
Note: for change NNN, NN := NNN mod 100 (e.g. for NNN=187, NN=87).
git fetch gerrit refs/changes/NN/NNN/*:refs/changes/NN/NNN/*
Based on: https://blogs.gnome.org/markmc/2011/09/25/gerrit-patch-review-from-the-command-line/
NON-git
find most recent files, recursively
find DIRNAME -type f -print0 |
xargs -0 stat --format '%Y :%y %n' 2>/dev/null |
sort -nr |
cut -d: -f2- |
head
vim: various stuff
vim: reopen all files edited before crash/kill
[FIXME]
vim -r $(find . -regex '.*/\.\(.*\.\)?sw[po]')
# or, vim -p + 'cut'? kinda:
vim -p $(find . -regex '.*/\.\(.*\.\)?sw[po]' | sed 's/\.[^.]*$//' )
# maybe better:
vim -p $(ls -1t $(find . -regex '.*/\.\(.*\.\)?sw[po]' ) | sed 's#/\.\([^/]*\)\.[^.]*$#/\1#')
Based on: :help recovery
vim: new buffer (pseudo-“scratch”)
:new
Source: vim wikia
vim: insert/paste current directory name
Useful for naming Go packages. Uses the “expression register” "=
.
In normal mode:
"=expand("%:h:t")<Enter>p
In insert mode (equivalent but using <C-R>
):
<C-R>=expand("%:h:t")<Enter>
For more info about %:h:t
etc., see :help filename-modifiers
.
Various often used stuff
Windows, tabs, buffers
- [Ctrl-w], [Shift-T] — “promote” current window into a new tab
:tabmv -1
— move current tab 1 position to the left (similar for +1 etc.):tabcl
— close current tab:tabo
— leave only current tab (close all others):tabdo windo e
— reload all buffers in all windows in all tabs
Quickfix window
:cex system('go build ./...')
— run specified command and load the result in quickfix list. If the result can be parsed using ‘errorformat’, cursor will be moved to position of first error.- …
| copen
— add after above command to also show the quickfix window
- …
:cn
/:cp
— jump to next/previous error from quickfix list:ccl
— close quickfix window
[TODO] describe stuff in ‘set errorformat’
Registers (copy, paste, …)
:let @a = "foobar"
— put textfoobar
in registera
:let @f = @%
— put current filename in registerf
; can be then reopened in a different window with:e <C-R>f
ack: exclude some files from search
Source: stackoverflow.com
To exclude *_test.go (and also pipe through less while keeping colours and grouping):
ack --go $PATTERN \
--pager='less -R' --ignore-file=match:_test.go
Other examples of excludes:
--ignore-dir=_vendor
--ignore-file=match:'\.(txt|out|log)$'
ssh: break hanged session, and other tricks
Source: stackoverflow
[Enter] [
~
] [.
]
Also, to break out of a nested hanged session (i.e. ssh within ssh), repeat [~
] n times. E.g. for session 1 level deep:
[Enter] [
~
] [~
] [.
]
Other tricks:
[Enter][
~
][#
] — list forwarded ports in current session[Enter][
~
][?
] — list all available~
-commands
Source: lonesysadmin.net (via)
ssh: screenshot of remote machine’s display
$ ssh -t -i $PRIVATE_KEY $USER@$MACHINE 'sudo -u $GUI_USER bash -c "DISPLAY=:0.0 import -window root -screen /home/$GUI_USER/foo.png" '
[sudo] password for $USER:
Connection to $MACHINE closed.
ssh: reverse tunnel
- on $LOCAL machine, pick $USER via whom the tunnel will be built
if $USER has SSH login disabled, enable it temporarily:
LOCAL$ sudo usermod --expiredate "" $USER LOCAL$ sudo passwd -u $USER
deploy private SSH key on $REMOTE machine (e.g. as $KEY_PATH), and put the public counterpart of the key in /home/$USER/.ssh/authorized_keys on $LOCAL machine
Note: the private key must have
chmod 400
setup a reverse tunnel, on $REMOTE machine:
REMOTE$ ssh -i $KEY_PATH -o StrictHostKeyChecking=no \ -Nf -R 16003:localhost:22 $USER@$LOCAL
login via the reverse tunnel:
LOCAL$ ssh localhost -p 16003
do what you need via reverse ssh…
cleanup:
REMOTE$ rm $KEY_PATH REMOTE$ ps aux | grep ssh REMOTE$ kill ... # kill the process from step 4
If step 2 was done, reverse it:
LOCAL$ sudo usermod --expiredate 1 $USER LOCAL$ sudo passwd -l $USER
ssh: debug connection problems
On server
If possible (root access), run an extra instance of sshd on a distinct port, with detailed logs printed to console:
$ sudo /usr/sbin/sshd -d -p 2222
Source: unix.stackexchange
On client
Run ssh with -vvv
flag for detailed logs. Together with the extra server as above, this may look like:
$ ssh -vvv -p 2222 $USER@$HOST
Source: askubuntu
ssh: view fingerprint of server host key
Best solution:
$ ssh-keygen -E md5 -lf <( ssh-keyscan localhost 2>/dev/null )
$ ssh-keygen -E sha256 -lf <( ssh-keyscan localhost 2>/dev/null )
Sources: unix.stackexchange [1] [2]
Alternative:
$ ssh-keygen -E md5 -lf /etc/ssh/ssh_host_rsa_key.pub
$ ssh-keygen -E md5 -lf /etc/ssh/ssh_host_ecdsa_key.pub
One-liner:
ls -1 /etc/ssh/ssh_host_*.pub | join -j2 <( printf "md5\nsha256" ) - | awk '{system("ssh-keygen -E "$1" -lf "$2)}'
same but wrapped:
ls -1 /etc/ssh/ssh_host_*.pub |
join -j2 <( printf "md5\nsha256" ) - |
awk '{system("ssh-keygen -E "$1" -lf "$2)}'
Sources:
- cartesian product in bash: comment on catonmat.net
ssh: view remembered/stored fingerprints of hosts
For all hosts:
$ ssh-keygen -l -f ~/.ssh/known_hosts
$ ssh-keygen -l -f ~/.ssh/known_hosts -E md5
For single host:
$ ssh-keygen -l -f ~/.ssh/known_hosts -F $HOST:$PORT
$ ssh-keygen -l -f ~/.ssh/known_hosts -F $HOST:$PORT -E md5
Source: stackoverflow
Go: tips, tricks & patterns
Windows: ignore vendor in go test
Powershell script [TODO: how one runs it?]:
$GOPKG = (go list ./... ) | Out-String -stream | select-string -NotMatch vendor
iex "go test -v $GOPKG"
Source: golang.org/issue/15355
Pattern 1: poor man’s pattern-matching switch
func ... {
type change struct {from, to X}
switch (change{a, b}) {
case change{Foo, Bar}:
...
}
Pattern 2: easy reentrant Close for goroutines
func NewX() *X {
x := &X{
quit: make(chan struct{}),
}
go x.loop()
return x
}
func (x *X) Close() error {
<-x.quit
}
func (x *X) loop() {
for {
select {
case x.quit<-struct{}{}:
close(x.quit)
return
case y, ok := <-x.myChan:
if !ok {
// myChan closed, but we still have to allow x.Close()
close(x.quit)
return
}
// ... real work ...
}
}
bash: keyboard shortcuts
Commands reuse
- [Esc], [#] (or [Alt-#] or [Alt-3] or [Esc], [3]) — insert comment sign (“#”) at start of current line, then cancel the line (like Ctrl-C), saving it to history (for later fixing/completing & reuse)
- [Alt-.] — paste last argument from previous command (press again for earlier commands)
- [Alt-n], [Alt-.] — paste n-th argument from previous command (starting from 0)
- [Ctrl-r], some-text — incremental search backwards through history
Moving, editing
- [Ctrl-a] / [Ctrl-e] — move to start/end of current line
- [Alt-b] / [Alt-f] — move 1 word backwards/forwards
- [Ctrl-k] — kill (delete) part of line after cursor (to line end)
- [Shift-PgUp] / [Shift-PgDn] — scroll terminal window up/down
bash: tee 1st line to stderr as header
sed 1w/dev/stderr
Source: GNU sed manual
netstat: what’s listening on port
sudo netstat -l -p | grep $PORT
-l
— show listening server sockets-p
— show PID/program name- (
-W
— wide: don’t truncate IP addresses)
apt-get: Ubuntu packages installer
List files in package
For installed package:
dpkg-query -L $PACKAGE
Other possibilities: http://askubuntu.com/a/32509/111779
virtualbox: fix after upgrading Linux kernel version
$ sudo dpkg-reconfigure virtualbox-dkms
$ sudo dpkg-reconfigure virtualbox
$ sudo modprobe vboxdrv
(via)
psql: human-readable bytea fields in Postgres
set bytea_output='escape';
(via)
socat: forward serial (COM) port over SSH/TCP
Login to remote server with serial port, then start serving the port:
client$ ssh -L 3334:localhost:3334 server
server$ sudo socat -ddd -ddd /dev/ttyS0,raw,b115200,$(cat stty-flags | sed '1,4d' | sed 's/-\([^ ]*\)/\1=0/g' | tr ' ' '\n' | grep -vE 'cmspar|iutf8|extproc' | paste -d, -s ) tcp-l:3334
Create a local virtual serial port (will get assigned a name in /dev/pts/*
) forwarded to remote one:
client$ sudo socat -ddd -ddd pty,link=foobar,raw,echo=0 tcp:localhost:3334
curl: download from domain on virtual host by IP
$ curl --resolve "named-host.com:80:$IP" http://named-host.com
Source: some stackoverflow
openssl: view decoded details of a certificate
$ openssl x509 -in $CERTFILE.cer -noout -text
Source: serverfault.com
openssl: view expiration date of website’s certificate
$ echo | openssl s_client -connect $HOST:443 2>/dev/null |
openssl x509 -noout -enddate
notAfter=...
Source: realguess.net
openssl: fingerprints
Fingerprints for ~/.ssh/authorized_keys{,2}:
cat ~/.ssh/authorized_keys | xargs -n1 -I% bash -c 'ssh-keygen -l -f /dev/stdin <<<"%"'
same but wrapped:
cat ~/.ssh/authorized_keys |
xargs -n1 -I% bash -c 'ssh-keygen -l -f /dev/stdin <<<"%"'
Host fingerprints: see SSH command above
IP: check publicly visible IP
Any of the following should do:
$ curl ipinfo.io/ip
$ curl ifconfig.me
$ curl icanhazip.com
$ curl ident.me
$ curl checkip.amazonaws.com
Source: askubuntu.com
python: simple WWW server
$ cat ... > index.html
$ python -m SimpleHTTPServer $PORT
Source: gist