Shared publicly  - 
 
Best +Git tip I learned in a long time:
gitk ORIG_HEAD..
after pulling a branch from someone.
You can also do:
git shortlog ORIG_HEAD..
or
git diff --stat --summary ORIG_HEAD..
as well.
And if things went wrong:
git reset --hard ORIG_HEAD
to revert the pull (although I thought there was some other way to do that, but can't remember it at the moment.)

Many thanks to +David Miller for that one, it's already proving to be indispensable.
59
25
Thiago Macieira's profile photoTom Arnold's profile photoJean-Noel Avila's profile photoCarlos Silva's profile photo
22 comments
 
You didn't know about ORIG_HEAD?

That's literally a "Day One" feature of git, exactly because it's so incredibly useful (especially to a maintainer). We had ORIG_HEAD back when you had to script your stuff manually and bang two rocks together to make git do anything at all.
 
Wait, you don't need rocks to make git work?
Damn, I've been doing it wrong all this time...
 
Btw, I don't know if you actually tend to have a dirty tree (I often have my own local changes uncommitted in mine), but if you do, then "git reset --hard ORIG_HEAD" will not just go back to the pre-pull stage, it will also throw away all your dirty state.

So I'd suggest using "git reset --keep ORIG_HEAD" instead, which will also reset back to ORIG_HEAD, but it will keep your local changes around.

But that "--keep" option is reasonably recent, so it doesn't go back to the stone age of git like ORIG_HEAD does.
 
FYI the Linux foundation provide git trainings :-)
 
+Linus Torvalds yup, I'm slow. But to be fair, I never had to do merges until the past few years, and it picked up only this last year, with pull requests from sub-maintainers. Before that I only took patches through email.

Thanks for the --keep option hint, yes, I do have a dirty tree with local changes uncommitted.
 
git stash save, also is nice for uncommitted stuff while jumping around in history
 
git rocks :)
thanks +Linus Torvalds for creating it. Just used rebase to split out a patch and change the history around. it's that usefull!
 
Btw, if you now do more merges and you actually get conflicts, git can be really helpful for those. However, it does take some getting used to, and knowing the tricks. If you do, however, you'll never want to do conflicts any other way.

I used to edit patches in my sleep, and patch conflicts meant that I would just fire up the editor on the patch and the file it conflicted on, and see why it conflicted - and then just edit the patch to not conflict any more.

And I still do that occasionally, especially when somebody sends me a corrupted patch that conflicts due to some stupid whitespace issue or something.

But more commonly, if the patch isn't corrupt, I will just start a new branch at an earlier point (estimating where the patch sender started, because they seldom say so explicitly), and apply the patch there. And then just use git to merge it all - exactly because git is so very very helpful when merging.

The trick about merging is to learn to use

gitk HEAD...MERGE_HEAD <path-you-care-about>

(note the three dots between HEAD and MERGE_HEAD) with the caveat that if renaming has been going on, git will have noticed that rename at merge time, but in order to see all of it in gitk you need to give both the old and the new pathnames.

That gives you the history of that pathname in both branches, so now you can see what the conflict was all about. Often it's a "oh, one side did a trivial rename, so I'll just take the other side of the conflict, and then do the rename in that" - which can turn what looks like a really nasty merge conflict into something totally trivial.

The other trick is one that I don't personally use, but some people like. Git defaults to the traditional CVS/RCS conflict markers, and I'm used to them, and they are fairly dense. But especially if you look at the conflict without also looking at the history in "gitk", the density can actually be a problem, because it will have thrown away the original state (ie CVS/RCS-style conflicts only show the two end states, because CVS doesn't even know the original common state).

To get the much more verbose - but sometimes more helfpul - 3-way merge format, do

git config merge.conflictstyle diff3

(or just edit the config file directly, that's what I do - the config file format was designed for humans). That way you will see what the common base state was in the conflict itself.

And use "git diff" a lot as you fix up conflicts. The format for unmerged entries can look odd (and can even be misleading until you learn what to expect), but after a while you really start grokking it, and then it can be very helpful and you'll know when the conflict diff "looks correct".
 
Side note: "gitk HEAD...MERGE_HEAD <list-of-unmerged-files>" can be shorthanded to just "gitk --merge".

So most of the time you can just do

gitk --merge <file-you-are-interested-in>

which is less typing and easier to understand. The reason I mentioned the HEAD...MERGE_HEAD syntax is that is something that works even outside of merging, and in particular it works even after you have resolved the conflict and done the "git add" on it (and the file is thus no longer in the set of unmerged files).

I also mentioned it because MERGE_HEAD is another of those magical things like ORIG_HEAD that have been in git since the dawn of time.
 
+Linus Torvalds , it was a comprehensive intro to and push for *HEADs stuff. Thanks for the effort. And thanks to +Greg Kroah-Hartman to start this all, of course. I'll likely try to stick the merging part to my hands.

BTW, I think this post is a good example to point on two possible enhancements:
1. G+'s editor should be improved for writing good-looking manuals. :D
2. I'm more serious now. Each comment should be provided with a link/URL for easy reference/sending/saving. At the moment only the main post is link-able. It's not critical, but simple and helpful sometimes.
 
If you want to review all changes you've just merged:

git log -p --reverse ORIG_HEAD..

If you run into conflicts when merging and you need to figure out how to solve the conflict:

git log -p MERGE_HEAD..
and
git log -p ..MERGE_HEAD
 
+Linus Torvalds ah, thanks for the gitk --merge thing, that explains how you and Stephen Rothwell figure out the merge problem points so easily (I'm assuming he does the same thing) and will help out a lot in the future.

I too am used to the rcs merge comments, the diff3 ones just look "odd" to me.

And yes, 'git diff' does look weird, but after a while it too makes sense.
 
+Greg Kroah-Hartman: the one thing to look out for with "git diff" is that it will show up as empty if you've selected everything from one branch.

That's very much tied into how "git diff" really works (and it is true of the conflict diffs shown for merge commits after-the-fact too), and it is generally exactly what you want: if you've picked one side as the resolution to the conflict, the conflict is now "gone".

HOWEVER.

It does mean that if you incorrectly picked one side of the conflict, and didn't really understand what the conflict was about, the conflict now becomes totally invisible to "git diff". So while the diff output is wonderful for merging, it does have the caveat that incorrect merges can become very hard to notice, because there is absolutely no sign of them left.

The reason I mention this is because I suspect the "empty git diff" thing tends to sometimes lull people into a false sense of security: "the conflict is gone".

So after a particularly subtle merge, I often look at several diffs:

- The plain "git diff <filename>" (before doing a "git add" to finalize the resolution) shows very nicely how the same area picked parts from both sides.

- Doing a "git diff HEAD <filename>" and "git diff MERGE_HEAD <filename>" then shows how the different "sides" of the merge got modified by the merge.

Also, note that while "gitk --merge" is really useful, it is limited to showing the changes at a file boundary. And while that is usually what you want, sometimes it means that you may have tons of changes to that particular file that simply aren't relevant to the particular merge conflict. Using the "search" thing in gitk does help ("Ok, that commit doesn't modify anything around the conflict"), but it can sometimes be easier to just use the normal text-format "git log -p" model to more easily look for the changes that are relevant to the particular conflict (and search within 'less' for the code that conflicts).

The same arguments that work for "gitk" work for "git log" too, so you can do "git log -p --merge <pathname>". And with "git log" you can also then use arguments like "--grep" or "-S" to limit the commits you even see (--grep greps the commit message, and -S is useful if you have a particular string that you know changed in both branches: you can then use -S to show only the commits in which that string was introduced or removed).
 
+Jonathan Corbet I see a LWN article in the making.
+Linus Torvalds Maybe the Linux foundation should sponsor a day where you look all maintainers over the shoulder so that any unproductive work flows can be avoided. They could also sponsor beer for the afternoon/evening ..
 
Yeah, I've been doing something similar for a while, except that I use tig instead of gitk. The problem with ORIG_HEAD is that it doesn't work with other branches, so I also have this cute alias in my `~/.gitconfig`:

new = !tig --no-merges $1@{1}..$1@{0}

(although I'm sure some people here will cringe at seeing that --no-merges flag there)
 
Thanks for the tip.Credits to you & david :)
 
Thank you Greg for the white blind light
Git
 
Another trick to get a patch that no longer applies to your tree is to give "--3way" option to "git am". It does an equivalent of "guess which old version the submitter based the patch on, apply it and attempt to merge" internally.
 
+Git I just tried that, and it didn't seem to work:
$ git am -s --3way ../s
Applying: sysfs: get rid of some lockdep false positives
fatal: sha1 information is lacking or useless (include/linux/sysfs.h).
Repository lacks necessary blobs to fall back on 3-way merge.
Cannot fall back to three-way merge.

I guess this doesn't work if the patch sent to me doesn't have git commit ids in it, right? It is a "plain" patch.
 
+Git ok, nevermind, I tried it with other patches, that were generated using git, and it worked great.
But now I don't have an excuse when rejecting patches saying that they didn't apply properly because they made them against an older version of my tree :(
Add a comment...