I had these files with very very long lines of text on each line. It was paragraphs worth of words but not word wrapped. These files were stored in a git repository. Now and then, someone would change a word. Diff with line based output was difficult to find what actually changed.
I figured there must be a way to see just the words. A little searching around the docs and I found it.
> git diff --word-diff=color
Perfect. I still got ling scrolling lines though. You can override that with your $GIT_PAGER variable or I just piped the output manually for a one time fix:
> git diff --word-diff=color | less -r
Much easier to see the changes!
So there you are, using git to store, track and share your code with a few others. Maybe many others. You make a change, someone else makes a change, one or the other of you pulls the others changes and BAM.. you get that merge commit. It really isn’t harmful of course, but it cleans up your repository a lot to get rid of them. So…
- When you pull, use –rebase.
git pull --rebase
There. It did it for you. All your commits go after the commits on the remote origin.
- You forgot to do that. No prob…
git pull # oh man.. I forgot.. merge commit
git rebase origin/master # There. Pretty easy isn't it.
So of course, you might have the same issue if you were working on a branch. You check out master, make some commits, go back to your branch, make some more, etc. It works the same way.
# on your branch
git rebase master
There. You can pull in the master branch changes but put all your branch changes after so you don’t have to have the merge commit again.
So you wrote that branch, changed master, and then you merge your branch back to master and get a merge commit again. In this case there isn’t a ref to rebase off of so intuitively like remote/origin or master. No prob, just use gitk or git log or whatever to find out what the sha1 of the old master was before you made your merge.
There. No merge commit again.
Now, there are a bunch of more advanced things rebase can do. You can use it to edit commits that weren’t quite right. You can also change the order of commits, edit the commit message, drop commits completely, and other cool things. You can do it all interactively too…
git rebase -i # fun for all!
I leave you to study that part on your own.
Do you like gitk? I find it almost invaluable in merging, branching, looking at old revisions, diffs, etc. I find it annoying that git log is hard to glean the same information. I searched a round a bit and found that git log is quite configurable as to what it outputs. Here is a simple alias that outputs the log with some of the data you’d find by viewing gitk.
git config alias.logk 'log --graph --pretty=format:"%h %ae: %s" --decorate --abbrev-commit'
You can add –global so you don’t have to make a logk alias for every repository.
You can also read the man page for “git log” and change the format to suite your liking.
So you just committed 15 things to your git repository and now you want to push your changes. Oops, commit #2 added your password file. Or perhaps you misspelled words in the commit message. Now, being a git expert, you think to yourself, I’ll just create a temporary branch, cherry-pick the commits that are correct, re-commit correctly the incorrect commit, and then merge/push my temporary branch instead of this flawed branch I have. That all works fine, but luckily there is a much easier way to do it.
> git rebase -i
When you use ‘-i’ with rebase, you get an interactive edit screen that gives you an option for each commit _after_ the sha1 you enter. For each commit you can either delete the entry entirely or replace the word “pick” with “edit”. Deleting an entry causes that commit to lost. Editing a commit gives you the option to unstage some of the files, edit the commit message, or really, to do whatever you want to change it how you intended. If you edit, or the rebase has a conflict, after setting things how you like, just use rebase –continue to go on your way.
According to the documentation for svndumpfilter, you can include one subcommand when filtering a dumped repository. Suppose you have a repository that has a path “/some/path” that you’d like to separate out into its own new repository. From the documentation, you simply pipe the original dumped repository through the svndumpfilter command.
cat repos-dumpfile | svndumpfilter include some/path > new-dumpfile
The caveat is that if there are paths copied from other paths in your repository that the include argument does not cover, you’ll get an error. I got around this command by piping the output from one svndumpfilter command to another, each with exclude commands instead of include commands. The result leaves only the paths I want, but included the alternate copy branch that I had used part way through the coding process.
cat repos-dumfile | svndumpfilter exclude unwanted/one | svndumpfilter exclude unwanted/two | svndumpfilter exclude unwanted/three --drop-empty-revs --renumber-revs > new-dumpfile
Notice on the last svndumpfilter command, I added a couple arguments to renumber the repository revisions and drop the empty revisions. While these are of course optional, in my opinion, they make the new repository cleaner.
The subversion book states you can edit the Node-Path values in the dumped file to have the new repository imported at different paths. I chose to simply issue an “svn mv” command once I imported the repository.