Archive for November 2011
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.)
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
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
Delete a specific commit
Use rebase -i, again.
git rebase -i <commit>~1
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.