Some common tasks. All of these are available on the web.
git checkout --orphan gh-pages
to see how to set up a
completely empty branch.git stash; git push origin stash@{2}:refs/heads/otherstash
git format-patch HEAD^ path/to/file
Suppose, for whatever reason, you want to change a commit back in your commit history. That is, you want to edit just that commit. This is not difficult, and can be done as follows.
Adapted from SO:
Suppose you want to change some code back in commit c0bec38, run
$ git rebase --interactive c0bec38^
edit c0bec38 a note about closures
pick 82afaf2 default arg for lambdas
pick d096072 some concrete examples of isotropic vectors
pick 88a35c9 tfidf - formatting
Choose the appropriate commit and modify ‘pick’ to ‘edit’. After making changes and commiting, tell git to amend all following commits without editing on each:
$ git commit --all --amend --no-edit
Then $ git rebase --continue
Note that this changes the SHA-1 of the edited commit and every commit
forward from the edited commit. This is the usual consequence of using
git rebase
, and force pushing the rewritten history will break anyone
else’s clone.
Super useful stuff.
From Github’s “Splitting a subfolder out into a new repository” we get this little pearl:
git filter-branch --prune-empty --subdirectory-filter tfidf master
Here’s a spiffy way to change all the author and committer information in an existing git repository, by defining an alias.
[alias]
change-commits = "!f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch --env-filter \"if [[ $`echo $VAR` = \\\"$OLD\\\" ]]; then export $VAR=\\\"$NEW\\\"; fi\" $@; }; f"
#from https://help.github.com/articles/remove-sensitive-data
#remove-file = "!f() { git filter-branch -f --index-filter \"git rm --cached --ignore-unmatch $1\" --prune-empty --tag-name-filter cat -- --all; }; f"
I need to work up a scratch git repo locally to explore this script alias in more depth.
Invoke it with the following:
git change-commits GIT_AUTHOR_EMAIL "david.doolin@gmail.com" "johnhenry7@yahoo.com" -f
The -f
is force, which will be necessary after the first change.
The values which can be changed are:
GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_COMMITTER_NAME
GIT_COMMITTER_EMAIL
pick abcd Someone else's commit
pick defg my bad commit 1
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD
pick 1234 my bad commit 2
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD
All my game stuff goes under the “johnhenry” identity, to keep a nice firewall between work and play. Here’s what needed to be done to fix up the consim github repo.
First is updating the identity locally to override the global identity:
git config user.email "johnhenry7@yahoo.com"
git config user.name "John Henry"
Next, fix all the previous commit information:
$ git filter-branch -f --env-filter "GIT_AUTHOR_NAME='John Henry';
GIT_AUTHOR_EMAIL='johnhenry7@yahoo.com'; GIT_COMMITTER_NAME='John
Henry'; GIT_COMMITTER_EMAIL='johnhenry7@yahoo.com';" HEAD
Note that each of these can be changed independently or in any combination. There is no need to change all at once.
Finally, change the remote with a force push:
git push -f origin master
The usual caveats for force pushing apply: don’t be a jerk if someone else is working from the same branch.
Reconfigure author and email, then git commit --amend --reset-author
Here’s a spiffy gist: https://gist.github.com/johnhenry/7f10d823530afd83a6bc
Sometimes a bad merge or rebase messes up a file irreparably. In this case it can be better to replace the entire file with it’s counterpart known to be good in another branch.
Suppose our rebase of Ruby Koans screwed up the local copy of README.rdoc. Here’s how to fix that:
git remote update # e.g., file is in upstream git checkout upstream/master -- README.rdoc git add README.rdoc git commit -m"Replaced botched README.rdoc with good from upstream/master"
Not difficult at all.
The following was quited from SO:
[–]
Show only commits that affect any of the specified paths. To prevent confusion with options and branch names, paths may need to be prefixed with “– “ to separate them from options or refnames.
Then, git checkout <commit hash> filename
.
Many ways, here are a few:
There is a good StackOverflow page for this.
Here’s a useful command, especially if working with a system like git
flow: git remote update
. git remote update
is equivalent to git
fetch --all
.
Here’s an example from Ruby Cabochons:
$ git remote --verbose update Fetching origin From bitbucket.org:doolin/cabochons = [up to date] feature/sti-sans-rails -> origin/feature/sti-sans-rails = [up to date] develop -> origin/develop = [up to date] feature/controllers-sans-rails -> origin/feature/controllers-sans-rails = [up to date] feature/stubs-mocks -> origin/feature/stubs-mocks = [up to date] master -> origin/master $
The --verbose
flag lists the relevant branches which are fetched.
From the git-remote
man page:
update
Fetch updates for a named set of remotes in the repository as defined by remotes.<group>. If a named group is not specified on the command line, the configuration parameter remotes.default will be used; if remotes.default is not defined, all remotes which do not have the configuration parameter remote.<name>.skipDefaultUpdate set to true will be updated. (See git-config(1)).
With –prune option, prune all the remotes that are updated.
From SO, How to delete a git
commit:
git reset --hard HEAD~1
Notes:
rails generate
), check for the
equivalent of a rails destroy
and back out only those changes.rake db:drop
to get rid of everything.rake db:migrate
to re-run the migrations.rake db:test:prepare
--hard
will blow away the cache and any changes not stashed.Answering the question above, git reset --soft HEAD^
should leave the
changes from that commit instead of destroying them. Since --soft
is
the default option, git reset HEAD^
uncommits. (TODO: Verify.)
git revert HEAD
Here’s a little kata:
mkdir gittest
cd gittest/
git init
vi file1.txt # edit 1
git add file1.txt
# git commit
vi file1.txt
git diff
git reset -- file1.txt # does nothing, haven't committed...
vi file1.txt
git commit -m"edit 1"
vi file1.txt # edit 2
git reset -- file1.txt # does nothing
git add file1.txt
git status # staged
git reset -- file1.txt
git status # unstaged
git checkout -- file1.txt # remove changes
less file1.txt
This is a good StackOverflow article on editing commits. Good git-rebase man page too.
This came about as I moved cucumber from :test, :development
to just
:test
to shut off some warning messages. The procedure went like this:
git rebase -i HEAD~2
git reset HEAD^
git add -p
to select the commits correctly.git rebase --continue
git rebase -i HEAD~3
to squash like commits.This turned out to be fairly easy.
For example:
GIT_COMMITTER_DATE="November 9, 2014, 2:41 PM" git commit
--date="September 21, 2014, 9:45 AM"
+
This bears deeper scrutiny: git push origin +master