Additional Git Notes

Russell Bateman
February 2014
last update:

These are to be added to gitk.html or somewhere better. (Some notes in that file aren't relevant to gitk and should be put elsewhere.)

The predicament

Imagine having done work a couple of files in a private branch, russ, consisting of several commits and pushes to origin russ, then needing to present the work in a code review. For convenience, you want the changes to appear as being the object of a single commit.*

(* Because of how change messages are expected to appear in the product repository with "reviewed by" notices and there's only going to be one review.)

Steps followed

This isn't the best way, but it allowed some useful exploration along the way.

Here's the history...

  1 gitk --all
  2 git checkout master
  3 git pull origin master
  4 git checkout russ
  5 git merge master
  6 git rebase --interactive HEAD~10
  7 git rebase --abort
  8 git reset --soft 611f07eb50c2c36f0370d114846f2164b0602142
  9 git reset --hard 611f07eb50c2c36f0370d114846f2164b0602142
 10 git rebase --interactive HEAD~4
 11 git push origin russ
 12 git reset --soft HEAD^
  1. Launched gitk to look at the state of things. The thing about gitk is that it shows us the SHA1 hashes in a way that doesn't make us squint.
  2. ...
  3. ...
  4. ...
  5. Switched to branch master to pull down latest changes. This turned out to be a mistake we'd correct later using git reset --hard. Here's why:
  6. We tried to rebase to squash the changes into one commit, however, git would not let us proceed (because of having pulled down and merged a huge mess of changes including some merge conflicts needing resolution).
  7. So, we aborted this.
  8. We reset soft, not wanting to lose any changes, to the hash that marked my last change in branch russ.
  9. We looked at IntelliJ and gitk, trying different things, then reached the conclusion we needed to do a hard reset. Not shown here: I copied the two files I'd changed to /tmp for safe-keeping.
  10. After the hard reset, we were back to where I started in step 1. We rebased again. This was successful. Doing this interactively, we picked the first commit (even though the oldest), squashed the other 3, then rewrote the commit message, which was in reverse order, to how we wanted to see it. Exiting vi, we were pleased to see this had all succeeded.
  11. We reinspected gitk, which still showed indentation for the commits since these commits had been pushed to origin russ. Afterward, we saw the commits as we wanted to see them.

  12. In order to appease IntelliJ's Changes view, we did a soft reset to the immediately previous commit. This allowed our list of (two) changed files to show up such that right-cliking Default would give us the sequence of views that we're used to seeing.

Steps that should be followed

This is the best (and shortest) way to have produced the effect we were looking for (without all the trial, error and exploration noted above). It's not an exact subset of the above, but includes a couple of other likely operations.

  1 gitk --all
  2 git rebase --interactive HEAD~4
  3 git log
  4 git reset --soft HEAD^
  5 git status
  6 git commit -a
  1. Launch gitk to view what we're up against.
  2. Rebase our four commits, pick one, squash the others, reorder the messages.
  3. List out our commit messages for use in the final commit. We'll need to save the console with these in it or copy the verbiage somewhere to use later.
  4. Do a soft reset to just before our work so that IntelliJ will pick it up for an easy and logical code review.
  5. Sanity-check to make sure our next commit will be (just) the two files.
  6. (Re)commit as if we'd meant to do one commit in the first place. This way, our single commit matches on a one-to-one basis the (lengthier) work we undertook in the first place.

Steps to the final commit

  1 git checkout master
  2 git pull origin master
  3 git checkout russ
  4 git rebase --interactive master
  5 gitk --all &
  6 git status
  7 git commit -a
  8 git rebase --interactive master
  9 git fetch
 10 git checkout master
 11 git merge russ
 12 git push origin master
 13 git checkout russ
 14 git fetch
 15 git push origin --delete russ
  1. ...
  2. Switch to branch master and make sure it's up to date.
  3. Switch back to branch russ.
  4. Attempt to rebase—failed.
  5. Launch gitk.
  6. Check git status.
  7. React to failure above by committing what we've done. Here is gitk after the commit.

  8. Attempt again to rebase (successful). Here is gitk after the rebase.

  9. At this point, use git fetch to get all status into both local repositories. Afterward, gitk appears:

  10. ...
  11. ...
  12. Merge branch russ into master and push:

  13. ...
  14. Then, switch back to russ and re-fetch:

  15. Finally, since we no longer need it (I use it more or less to ensure a back-up of my current, as-yet-unmerged work), let's delete branch russ' remote. This results in no change to gitk.

Console scrape of above

This is to help visualize what actually went on.

russ ~/fs/ct $ git checkout master
M	fs-api/src/test/java/org/familysearch/fs/api/sources/
M	fsbe-domain/domain-prod/src/test/java/org/familysearch/ct/impl/sources/
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
master ~/fs/ct $ git pull origin master
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
 * branch            master     -> FETCH_HEAD
Updating 4fa22e6..0694949
Fast-forward |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
master ~/fs/ct $ git checkout russ
M	fs-api/src/test/java/org/familysearch/fs/api/sources/
M	fsbe-domain/domain-prod/src/test/java/org/familysearch/ct/impl/sources/
Switched to branch 'russ'
russ ~/fs/ct $ git rebase --interactive master
Cannot rebase: You have unstaged changes.
Additionally, your index contains uncommitted changes.
Please commit or stash them.
russ ~/fs/ct $ gitk --all &
[1] 3048
russ ~/fs/ct $ git status
# On branch russ
# ...
#	modified:   fs-api/src/test/java/org/familysearch/fs/api/sources/
#	modified:   fsbe-domain/domain-prod/src/test/java/org/familysearch/ct/impl/sources/
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#	modified:   fsbe-domain/domain-prod/src/test/java/org/familysearch/ct/impl/sources/
russ ~/fs/ct $ git commit -a
[russ 31717a7] Added test for new method in FsReference. Refactored TestFsReferenceServiceImpl forCmisWrite.
 2 files changed, 627 insertions(+), 1293 deletions(-)
 rewrite fsbe-domain/domain-prod/src/test/java/org/familysearch/ct/impl/sources/ (64%)
russ ~/fs/ct $ git rebase --interactive master
Successfully rebased and updated refs/heads/russ.
russ ~/fs/ct $ git fetch
remote: Counting objects: 10, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 10 (delta 0), reused 3 (delta 0)
russ ~/fs/ct $ git checkout master
Switched to branch 'master'
master ~/fs/ct $ git merge russ
Updating 0694949..993a2df
 .../fs/api/sources/        |    6 +
 .../    | 1040 ++++----------------
 2 files changed, 190 insertions(+), 856 deletions(-)
master ~/fs/ct $ git push origin master
Counting objects: 42, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (17/17), done.
Writing objects: 100% (23/23), 2.74 KiB, done.
Total 23 (delta 10), reused 0 (delta 0)
To [email protected]:fs-eng/ct.git
   0694949..993a2df  master -> master
master ~/fs/ct $ git checkout russ
Switched to branch 'russ'
russ ~/fs/ct $ git fetch
russ ~/fs/ct $ git push origin --delete russ
To [email protected]:fs-eng/ct.git
 - [deleted]         russ

git fetch

git fetch says what has changed since—it doesn't pull anything down as does git pull.