

Things about Git - matheusml
http://www.matheuslima.com/things-you-didnt-know-about-git/

======
tomlu
> Last friday I lost a commit using git reset --HARD

You don't lose a commit just because you use git reset --hard. The author
either doesn't know how git branches work and/or how to use reflog, or he
means to say he lost the uncommitted content of his working tree.

~~~
matheusml
It was 'git reset --HARD <commit-id>', like a cherry pick, before pushing.

~~~
X-Istence

      git reflog
    

Might be your saviour here next time.

~~~
matheusml
I'll update the post. This worked for me. Thanks a lot!

------
masklinn
> If you want to check what it's difference between two branches, you can
> simply do: git diff branch1..branch2.

This won't give you the difference between two branches, it will give you the
commits in the second branch which are not in the first one (technically it
will give you the commits accessible from the second revspec which are not
reachable from the first one, they need not be branches).

This means you won't see things in branch1 which have changed since the
branches split.

If you want to see the differences between the two branches, you need to use
<rev1>...<rev2> (three dots)

In set-theoretic notation, the first one is `a(branch2) \ a(branch1)` while
the second one is `a(branch1) △ a(branch 2)` (where a is the ancestors-and-
self function)

> Most people just use git status, but you can pass arguments to change the
> way status is shown. With git status -sb you have an output like this:

> ## master > M Gemfile > M Gemfile.lock > M
> app/controllers/home_controller.rb > M app/views/home/index.html.erb

This is mixing 2 changes and missing important information:

-s will provide what most people are looking for here, that is an SVN-like "short status" with no prose or suggestion text. Because of the index, Git has 2 status flags, the index state (difference between repository and index) and the second one is the working copy state (difference between working copy and index). The flags also feature specific states for merging situations.

-b adds branch information to the short status format, as `local[...remote]` (with the remote being absent if the local branch has no configured upstream).

~~~
dima55
Hi. You appear to be too smart for your own good. "git diff A..B" is
synonymous with "git diff A B" (i.e. just compare the two points in the tree
without regard to their history). "git diff A...B" is equivalent to "git diff
$(git-merge-base A B) B" (i.e. ... does what you think .. does). The manpage
is very clear about this.

------
twic
> Last friday I lost a commit using git reset --HARD (shit happens), so I
> decided it was time to study

Mercurial?!

> git again

Aw.

It may be interesting to compare the safety nets that Git and Mercurial
provides. Mercurial tries to steer you away from rewriting history, but it
does supply a complete set of tools for doing it - it has rebase, strip,
commit --amend and so on. The difference is in what happens to deleted
history.

In Git, as i understand it, history is defined by the branch pointers and the
commits reachable from those. Deleting history simply means fiddling the
branch pointers; the underlying commits are still there, completely unchanged.
But now you can only find them via the reflog (unless you wrote their hashes
down or something). They will stay there until the next garbage collection
cycle. I don't know what determines when garbage collection occurs, so that
might be ages, or it might not be long.

In Mercurial, history is defined by the commit graph. If something is in the
graph, it's in history. That means that to delete something from history, you
need to actually remove it from the graph. Commits which are removed are
written as bundle files to the .strip-backup directory inside the repository's
.hg directory. These are compressed binary files, so they're not much fun to
look at directly, and i'm not aware of any way to display their contents, but
Mercurial can import them, so restoring the changes. These files are never
deleted automatically.

Really, Git's safety net is more tractable - once you have identified a
deleted commit, you can work with it in the same way as any other commit.
Mercurial's safety net is purely cold storage. I believe this reflects the
tools' different opinions on rewriting history: in Git, it's normal, so you'll
need the safety net a lot, whereas in Mercurial, it's not normal, so you will
only need it if you have been bad, and you should feel bad.

Fortunately, something that is slowly arriving in Mercurial is the concept of
changeset evolution:

[http://mercurial.selenic.com/wiki/ChangesetEvolution](http://mercurial.selenic.com/wiki/ChangesetEvolution)

Which basically keeps deleted commits in the tree, like Git, but marks them as
deleted. Moreover, when you do things like amend or rebase, it marks commits
as having been replaced by other commits. Those marks are in the committed
metadata, and are propagated between repositories, which means it becomes
possible to do things like safely rebase public commits, merge different
attempts at rebasing some commits, and more besides. If changeset evolution
works as well as is hoped, it will provide all the advantages of history
mutation without any of the drawbacks, which will be super sweet.

~~~
jordigh
Speaking of Evolve, I would like to promote my own talk + demo about it:

[http://www.youtube.com/watch?v=4OlDm3akbqg](http://www.youtube.com/watch?v=4OlDm3akbqg)

------
eogas
#3 is no longer the default behavior since 2.0 was released.

[http://blog.nicoschuele.com/posts/git-2-0-changes-push-
defau...](http://blog.nicoschuele.com/posts/git-2-0-changes-push-default-to-
simple)

~~~
pooper
> The 'matching' option is the default behavior in Git 1.x.

Is Git 1.9.2 (latest binary release for Windows) actually Git 2.x? By
definition, shouldn't 1.9 do matching rather than simple?

~~~
pooper
Downvoter, please comment on what you think I did wrong here? You clearly have
been here long enough to get downvoting privileges but I guess you failed to
learn proper etiquette? Maybe they ought to consider raising the bar to
something like 1000 points instead of 500?

------
jds375
Related, I'm sure many people here know this, but it's super useful for those
that don't. To undo any uncommitted work and go back to the original state of
the branch use: 'git checkout .'

~~~
syncsynchalt
I like doing a 'git stash' or 'git stash save deleteme' instead. That way if I
realize a moment later that I needed anything, it's still available (if I
haven't done a 'git stash drop' yet).

------
Watabou
Also useful:

    
    
        git checkout -
    

to switch to the previous branch. Similarily,

    
    
        git merge -
    

to merge the previous branch into the current branch.

------
ecoffey
Since it looks like the author is idling in this thread:

I'm a enthusiastic git user, and I've ranted about a few git topics here:
[http://gitdoctor.com/](http://gitdoctor.com/)

I also use the @gitdoctor twitter handle for helping people out in those
moments of "oh shit, what is happening?!" with git :-)

------
pooper
For people coming from TFS who might think stash is similar to shelve... stash
is local. It does not go to your remote (origin?) unless you do some special
gymnastics. I don't know if it is even officially supported to push a stash to
remotes.

~~~
mercer
> I don't know if it is even officially supported to push a stash to remotes.

I usually just create a temporary branch that I push upstream if I want to
save my 'stash'. Is there a use case I'm not thinking of where pushing a stash
upstream is useful?

~~~
lugg
The only use casei can think of is not knowing how easy branching and merging
is with git. Or someone coming from svn thinking branches take up a lot of
disk space and time. Stashes are meant to be local.

Its pretty easy to turn one into a branch too if you feel you should make a
stash available over the net.

------
fiatjaf
This post was mostly misleading and unnecessary.

~~~
pekk
Even if that's true, you're talking like a dick.

