Dialog with an intern, or, alternately, some random unixy tips and tricksAugust 8, 2016
mmeehan: actually i may be able to ask it on here if u have a moment
mmeehan: so for the [work task related] thing, I added another output field [task thing stuff] and then when i recompile, i get a GET request error for adding that [thing]
mmeehan: and i wasn’t sure if i was missing some other step?
jfo: show me the diff?
mmeehan: this is kind of difficult to read, without the syntax highlighting…
jfo: ooohhh pro tip!
jfo: how did you generate this
git diff commit#..commit# | gist
jfo: so, gist has a type param
gist -t diff or whatever the filetype is…
jfo: which will syntax highlight for you
mmeehan: [url to syntax highlighted gist of a diff]
mmeehan: thank u!!!
jfo: want another related awesome trick?
mmeehan: i like pro tips
jfo: this is a good one
jfo: this will blow people’s minds
mmeehan: ok i want to blow all the minds gimme
jfo: we think of diffs as just a git thing probably
jfo: but they are not
man diff to read about the diff tool, which is separate
jfo: diff is actually a like, really specific file format that originated in perl land, I think
well, actually, yeah…
patchwas written by Larry Wall in 1985, who later went on to write perl, but
diffwas a unix utility before that, authored in the early 70’s.
patchwas capable of taking the output from
diffand applying the changes to a file or a group of files.
jfo: here’s another one…
jfo: which you can use to apply a patch file
jfo: a “patch” is what
git diff produces and it’s what
git apply applies; a “patchfile” contains the plaintext diff.
Here’s a thing to try! Run some commands in an empty directory (not a git repo just an empty directory…)
printf 'hi mom\nhi dad\n' > 1.txt printf 'hi mom\nhi dad\nhello world\n' > 2.txt cat 1.txt cat 2.txt
Just makin’ some files! How are they different?
diff 1.txt 2.txt diff 2.txt 1.txt
diff 1.txt 2.txt > look_a_patch_file_omg cat look_a_patch_file_omg
We saved those differences into the patchfile… notice the name is inconsequential, it doesn’t need a suffix to describe a filetype.
Let’s apply that patch, then!
patch 1 < look_a_patch_file_omg
patch 2 < look_a_patch_file_omg
cat 1.txt cat 2.txt
This is basically all
git applydo, but the diff is taken from what a file looked like at a specified ref (a ref[erence] is a commit hash, or a branch name, or one of a few other things…), rather than another file on disk like above. I do not know why
jfo: it’s the same stuff
jfo: just wrapped into the git plumbing
jfo: so this is all to say that you can apply a diff directly to a working tree
git apply patch.diff or whatever
jfo: which is what I’ll do to “checkout” your changes in a really lightweight way
mmeehan: O0o0o0o i get it woow ahh thats so helpful! So whenever you want to see what someone else’s diff does on your own machine you just
git apply patch.diff
jfo: yup! or at least that is one way to do
it. It’s outside of a lot of the git tracking and checking out and branches and
stuff… it’s as if you typed all the changes in yourself. It doesn’t commit anything for
you, which means you can get back to a clean head with a
git reset --hard if
that is what you want
jfo: but you might have already known that…
mmeehan: i didn’t know about that
jfo: oh good!
jfo: well want more? theres another level that’s even more cool
jfo: I’m on a pedagogical roll here
mmeehan: go for it hahah
jfo: well, git apply reads a patchfile, just like patch does. As far as I can tell they pretty much do the same thing basically, just with different invocation syntax and I am sure there are more subtle differences but the main point is they both apply a patch file.
jfo: what about [url to raw gist of diff on github]
jfo: that is the diff we want
jfo: in plaintext… just that it’s living on the server right now.
jfo: would fetch the diff from the server and print it to standard out.
jfo: so from there…
jfo: you could
curl [url] > /tmp/file.diff, which redirects the diff into a temporary file,
omg did you know about
/tmp? It’s the best. Basically the whole directory gets cleaned out by the OS every so often, so for ephemeral crap that you just want to hold onto for a little while (tmporarily?) you can just put it in
/tmpand you will get cleaned up after.
jfo: and then
git apply /tmp/file.diff in the working tree
jfo: (the suffixes are inconsequential btw, just conventional, you don’t have to call it
.diff, it could be whatever you want)
jfo: but doesn’t it seem like you should be able to do that in one step?
mmeehan: yes it sure does
jfo: well you sure can!
jfo: in at least TWO different ways!
jfo: OMG I KNOW
jfo: you can pipe it like
curl [url] | git apply
mmeehan: so piping sends the output of the first command to the second command?
jfo: basically yes, when used like that the stdout stream coming from the left side command feeds into the stdin stream of the right side command. You can chain things as much as you want, btw, it’s the unix way tm. Want to know how many
README files are on your whole computer?
tree / | grep README | wc -l
jfo: That’s a terrible and inefficient way to do that, but it would totally work. I always forget the flag for multi pattern grepping and end up piping things through multiple instances of grep instead, like a wally.
mmeehan: what is curl exactly?
mmeehan: i feel like i have seen it in a few different contexts…
jfo: curl is a command line http client
jfo: you can do all sorts of stuff with it,
jfo: this is so fun
jfo: check this out
jfo: open a terminal window
jfo: and run
nc -l localhost 5000
mmeehan: what does nc do?
jfo: it’s short for ‘netcat’, which is a simple little utility that reads and writes data across networks.
jfo: ok ready?
jfo: then open another terminal window
jfo: and run
mmeehan: ok ok
mmeehan: what is happening
jfo: haha did it work?
mmeehan: o0o0o i see i wasn’t sure what nc is
jfo: curl is the most basic client, it sends simple get request headers and then prints the response to std out
If the commands worked you should have seen something like
GET / HTTP/1.1 Host: localhost:5000 User-Agent: curl/7.43.0 Accept: */*
Appear in the netcat window. Those are the ‘headers’ I’m referring to.
mmeehan: that’s crazy
jfo: you can also post with it, not sure of the flags off the top of my head…
jfo: :sparkles: networking :sparkles:
jfo: notice too, that
jfo: the window you ran curl in
jfo: is waiting on a response
mmeehan: yeah it’s so smart!
jfo: it will never get one, because it sent the request to netcat, which isn’t a server that knows how to handle that request, and it also isn’t piping to anything that responds, either.
mmeehan: this is supa cool
jfo: but you could wire up like, the dumbest server ever, using pipes and random utilities, probably
mmeehan: ooo right i see
jfo: but the last thing I was going to say
jfo: is this weird unix operator that I learned about last year
jfo: <(arbitrary commands or whatever)
echo <(cat /dev/random)
mmeehan: hmm i don’t understand the return
jfo: you get a path, right? to a device file!
jfo: which is weird, right?
mmeehan: yeah i got a path … where is it comin from? random? lol
jfo: under the hood, *nix is implementing interfaces to processes as device files, which represent streams in some form or another!
jfo: a usual path represents what we think of as data on disk
jfo: but a stream can come from anywhere… like a stream of audio data could be coming in through an analog to digital converter, which is an external device, that the OS interfaces with through a device file!
jfo: what that
<(...) command does, it exposes the internal device file representation of the process you run inside of it
jfo: so you can access the return of that process like any other file
jfo: that is to say
jfo: that this will also work:
git apply <(curl [url to raw diff])
jfo: and essentially it does the same thing as writing the curl output to a file with
curl [url] > /tmp/filename and then reading it with
jfo: but it skips the writing to disk step
jfo: computers! :D
jfo: now, I will actually look at the diff
mmeehan: this all sounds cool but i would have to read more into device files and streams and such to fully grasp the awesomeness …
jfo: yeah it’s a little mind bendy!
jfo: sorry for getting excited about it!
mmeehan: y r u sry i am glad to learn !!
jfo: you are right I am not sorry I am just being polite in case you hate this
mmeehan: i am excited to understand it better … under the terminal hood
jfo: I should write this all up in a blog post or something
mmeehan: yeah !
jfo: oh yeah last tip for now and this is a small one
jfo: you can put ‘.diff’ on the end of any github pull request url
jfo: and you’ll get the raw diff of the whole changeset
jfo: try it!
jfo: either will work
mmeehan: right wow!
jfo: ok back to this ticket