Git suggestions for developers first starting on a medium/large team.
git blame foo/bar/baz.cs
Usually git clients / web applications have a more interactive way to do this:
In GitHub, you can click on a commit hash to see the blame
output from before
that commit. That's useful if, for example, Susan made a formatting change to
this line last week, but the thing you care about is when Andrew changed the
conditional logic on the line six weeks ago. From the command line it's not as
easy as clicking a link to move backwards in time.
git shortlog -s git shortlog -s --since "5 months ago"
src/controllers/CoolWidgetController
?git shortlog -s -- src/controllers/CoolWidgetController
The person with the most commits in that folder is probably a good start. If
they're not on the project anymore, try the next highest — or add a --since
filter to only look at recent commits.
If you are in the habit of putting the ticket slug in the commit message
git log --grep FOO-164
Or, try another search term instead of "FOO-164".
feature/foo
and branch master
?git diff --name-status master feature/foo
(If you're currently on branch feature/foo
you can omit "feature/foo" from the
end of the command.)
If you only care about files that have been, for example, deleted
git diff --name-status --diff-filter=D master feature/foo
See git help diff
and search for --diff-filter
for additional filters
(modified, created, etc.).
git branch git branch --all
And if you're looking for a specific branch, you can pipe the output to grep
(bash) or Select-String
(PowerShell) to narrow down the list.
git branch --all | grep foo
git log --name-only --pretty= --since "2 weeks ago"
This will likely contain duplicates, so you may want to clean up the output:
git log ... | sort | uniq
git log ... | Sort | Get-Unique
Note that the --pretty=
is setting --pretty
to ""
. The pretty command
determines what to show for the commit summary; by setting it to an empty value,
no commit summary will be shown. All you'll see is the --name-only
output that
lists the names of affected files.
git log --author "My Name" --since "1 week ago"
When you know that the code worked at a certain commit (say, 1 month ago) but
doesn't work now, git bisect
will help you efficiently search through all the
commits between then and now to find exactly which commit the regression was
introduced in.
It's a more complicated command, see the git bisect docs for details. The gist of it is that it performs a binary search of all commits between the known good and known bad commits. Either you check each commit manually and tell git that it's "good" or "bad", or you provide git with a script to check if a given commit is "good" or "bad" automatically.
This command does change your working copy, so make sure all your local changes are committed or stashed before the following:
git merge --no-commit --no-ff master git diff --cached git merge --abort
(Or if you want to go through with the merge: git merge --continue
)
You've messed something up, now what?
Don't worry, it's not gone! There's a detailed walk-through on this blog post: Recover a git branch you accidentally deleted. The key idea is:
git fsck
to list all the unreachable commitsgit fsck --full --no-reflogs --unreachable --lost-found | grep commit | xargs -n 3 echo | awk '{ print $3}' | git log -n 1 --pretty=oneline
git checkout <the-hash> -b your-branch-name
The details are all in that blog post.
Maybe because you merged the wrong branch in and then kept committing, or because you started work in the wrong branch, or for whatever reason you have a commit you don't want followed by a commit you do want.
temp
)git cherry-pick <commit-hash>
, fixing any merge conflicts as they arrivetemp
branch.Now, the branch that was once all messed up has only the commits you want, on top of branch that you meant to be building on top of.
This one's straightforward:
git commit --amend
Find the commit hash of the commit before the one you want to rename, then:
git rebase -i <that-hash>
In your editor, you will be presented with a list of all the commits between the
one you specified, and the current HEAD. To the left of each commit that you
want to rename, replace pick
with reword
. Git will re-apply each commit one
at a time, and for the ones you marked as reword
you will be prompted to edit
the commit message.
Maybe you notice that two commits back you have several commits with a summary "wip" and "more wip". Those should probably be combined with the commit after them.
As with rewording commit messages, identify the commit hash of the commit before the ones that you want to combine, then:
git rebase -i <that-hash>
Choose fixup
to discard a commit's message, or squash
to add the message to
the following commit. Like reword
, you'll have the chance to revise the
commit message.
The full options for rebasing are (you'll see this help message when you execute
rebase -i
):
# Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST.
Changing commit messages, combining commits, reordering them — these are ways to rewrite the git history.
git push --force
) — but the only way to find out if
someone's pulled is to ask themSomething to add? Continue the conversation on Twitter
Written 2019-05