Live data from Hacker News

On undoing, fixing, or removing commits in git

sethrobertson.github.io

71–74 of 74 posts

Re: On undoing, fixing, or removing commits in git

#71
post #68

Earlier quoted context omitted.

>I've never looked at .git/logs, but it looks like that is used by the `git reflog` command. It's basically a history (or log) of every commit that a particular reference has pointed to[1]. For example, I cloned the git source code: I think it's more or less the DAG represented as an adjacency list. I'd have to think a bit about why there is a separate log file for each branch. It seems that there's some redundancy i…

> I think it's more or less the DAG represented as an adjacency list. I'd have to think a bit about why there is a separate log file for each branch. It seems that there's some redundancy in doing that, and I'm wondering what the advantages and disadvantages are of splitting the history up in that way. Think of each branch as a pointer. Then realize that you can make that pointer point anywhere on the DAG, even to pa…

I noticed that there is no delta compression until objects get incorporated into a pack.

>Think of each branch as a pointer. Then realize that you can make that pointer point anywhere on the DAG, even to parts of the DAG that have no connection to each other. The `reflog` is a (local, non-comprehensive) history of where that pointer has pointed.

I got that branches were pointers. Now that I'm aware that the DAG is fully represented inside objects, I can see that what's inside logs/ is actually just logs. Each log corresponds to a subgraph of the full DAG. Getting history from a log would be more efficient than from the objects themselves, because to get it from objects, you'd have to dereference a lot of object references.

>I'm not sure what branches living under .git/refs has to do with excessive hierarchies/trees. There are enough things stored in the .git directory, that if you mashed them all together it wouldn't make any sense.

Having to descend through layers of subdirectories makes things harder. I'd reduce the depth of the directory tree to the absolute minimum. It's hard to tell if this is the minimum without knowing exactly what all the implementation constraints might have been.

I can see that the real meat of this system is the object store. It's useful to know about `git cat-file` for inspecting it.

Re: On undoing, fixing, or removing commits in git

#72

Earlier quoted context omitted.

An easy way to do that, is the way I tend to do it; Create a new branch based off the one you're rewriting history in, and that will actually keep all of that for you even after you rewrite it all. Makes it really easy to restore later with git reset if you need it.

Yes, this is how beginners should be taught to "back up" in git.

In the interest of making this easier:

    git branch branchname-backup
    #do dangerous stuff ...
    # whoops I just broke the branch really bad I'll start over
    git reset branchname-backup

Re: On undoing, fixing, or removing commits in git

#73

Earlier quoted context omitted.

git filter-branch will let you remove content permanently and irrecoverably if you really need to. Regarding uncommitted changes: This is in the same category as forgetting to do your backup before starting to mess around, IMO. I would encourage anyone to simply get used to committing extremely often and just using a quick interactive rebase before pushing.

At the last job where I used git, I'd work in a separate branch, and I started using `git merge --squash` to merge into the main branch to keep the history from getting too difficult to follow. When git merges a bunch of different histories into one, it becomes almost impossible to make sense of if people make lots of small commits. I shy away from `git rebase`, because it seems dangerous.

Never fear! "git rebase" isn't nearly as dangerous as many have been led to believe... unless you start rebasing things you've already published/pushed elsewhere. In that case you need to be very proactive about notifying everyone who could possibly have checked out your branch, etc. Otherwise: it certainly takes a little getting used to, but I find a little one-on-one "mini-mentoring" others with the first few rebases helps them immensely, so if you have someone who can help you in person it might be a lot easier to get comfortable with the process that way.

Re: On undoing, fixing, or removing commits in git

#74
post #68

Earlier quoted context omitted.

> I think it's more or less the DAG represented as an adjacency list. I'd have to think a bit about why there is a separate log file for each branch. It seems that there's some redundancy in doing that, and I'm wondering what the advantages and disadvantages are of splitting the history up in that way. Think of each branch as a pointer. Then realize that you can make that pointer point anywhere on the DAG, even to pa…

I noticed that there is no delta compression until objects get incorporated into a pack. >Think of each branch as a pointer. Then realize that you can make that pointer point anywhere on the DAG, even to parts of the DAG that have no connection to each other. The `reflog` is a (local, non-comprehensive) history of where that pointer has pointed. I got that branches were pointers. Now that I'm aware that the DAG is fu…

> Each log corresponds to a subgraph of the full DAG

I don't have the time to keep up this conversation, but this assertion is wrong. It is not a subgraph. It is a history of the values that the pointer was pointing to (e.g. "Pointer changed from pointing to value AAA to value BBB due to action XXX"). That is basically what all of those entries are. 'AAA' and 'BBB' maybe be in completely unconnected sections of the DAG.

If you create a new repository and add a couple of commits, then yes the reflog files will look like a history, but only because the branch pointer has traversed the DAG from start to end with no deviations.

For example you can have a DAG like this:

   A - B - C - D - E

   X - Y - Z
If you change the branch pointer to move from B to Z, this is not a subgraph. Well, I guess technically you could call it sgraph of the history of the branch pointer, but it in no way corresponds to the DAG other than that all of the pointer values exist within the DAG. For example the following operations:

  git clone
  git reset --hard Z
  git reset --hard X
Would create a graph like this (assuming that master pointed to E when you cloned):

  E - Z - X
Notice that this really don't correspond to the DAG other than the fact that those objects exist in the DAG.

Note:

- All of this information is only contained within the .git/logs files. None of it is stored in the objects themselves.

Post reply on HN