The Lumber Room

"Consign them to dust and damp by way of preserving them"

My Git personal reference

with 9 comments

Various git things I’ve had to look up from time to time.

(Always, while doing anything dangerous, have a gitk window open. Look, don’t guess. (Haven’t used gitk in a while.) And if you’re sharing your repository publicly, you can forget about most of the below.)

Git reset

What git reset <commit> does:
* Reset HEAD to the given commit
* (If not --soft) copy this new HEAD to the index
* (If --hard) copy contents of index to working dir

So, for example:
* To “undo commit”: git reset HEAD~1
This resets HEAD to HEAD~1, without copying this new HEAD to the index. So it’s as if you didn’t make the commit. You can go and commit in another branch if you want.

Copy commits from another repository

# 1. Add the other repo as a remote
git remote add other_repo_nickname <other repo's path/url>
# 2. Fetch its data. (pull = fetch + merge, so we want only fetch, not pull)
git fetch other_repo_nickname
# 3. The rest should be familiar
git cherry-pick <commit>

Note that you don’t need to specify the remote’s name for cherry-picking. Once you have fetched, all commits, even those originally from the other repo, can be identified just by hash. (If you want to refer to commit by branch, then you can identify it with “other_repo_nickname/branch_name”.)

Swap commits (reorder top two commits)

 git rebase -i HEAD~2 

and in your editor, reorder the two “pick” lines. (See here.)

Recovering commits deleted with reset --hard

In general, these are garbage-collected after 30 days (or when you run git prune or git gc), so you shouldn’t use reset --hard at least without doing a stash first.
If the garbage-collection hasn’t happened yet, get the sha1 hash of the commit with

 git reflog 

then make sure the commit is what you want with

 git show sha1 

and get the commit back with

 git cherry-pick sha1 

(or rebase or merge instead of cherry-pick, if that’s what you want.)

Squashing commits together, to keep your history clean

Use rebase. To squash the last n commits into one, do

 git rebase -i HEAD~n 

and change all “pick”s except the first one to “squash” (or “s”). See here and here.

Delete a specific commit

Use rebase -i, again.

 git rebase -i <commit>~1 

Delete the line for the commit you want deleted. See here and here.

Amend a specific older commit

This is tricky, and I don’t think I’ve seen it anywhere, especially for the case where there are branches that depend on it.
My solution: Find the first branch X that’s downstream from (= later than) it. Keep track of the whole tree downstream from X (take a screenshot if you must); you’ll need it. Checkout X, and do “rebase -i HEAD~[large enough number to cover the commit you want to amend]”. In the editor that pops up, keep all “pick” lines, changing only that one line you want to amend to “edit”. Save and close. Now git has stopped, allowing you to amend that commit. Edit the file. Do “commit –amend” (don’t forget to add all files you want included in that commit!). Do “rebase –continue”. You’re back at X now. Now for the first branch Y that was downstream from X, checkout Y, do “git rebase X”, and recurse on Y.
This doesn’t seem work (gets into rebase conflicts). Need to try again, and ask.

Written by S

Tue, 2011-11-29 at 10:06:52

Posted in compknow

Tagged with

9 Responses

Subscribe to comments with RSS.

  1. (Just noting down) another cool thing about `git rebase -i` is that you can rearrange commits by just rearranging the commit lines in the interactive window, to be used with ‘fixup’.


    Tue, 2011-11-29 at 12:52:43

  2. We had to delete a commit from our git repo once, the following worked (I don’t remember all the details of how this command works though :P ). I think this was marking the parent of any commit whose parent is 61f6e to ee56.

    git filter-branch –parent-filter \
    ‘test $GIT_COMMIT = 61f6e8c634420f2f6ff42f46a028e070685d22ed && \
    echo “-p ee5634334a139cf51db9491755f442a744155aa8” \
    || cat’ \
    –tag-name-filter ‘cat’ \


    Sat, 2011-12-10 at 12:31:35

    • now that think of it, this is slightly different from deleting the commit: it deletes the actual commit, but does not un-propagate the changes made in the commit.


      Sat, 2011-12-10 at 12:43:07

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: