Add updated files only

The secret option to save you some face
The git logo with the title of the article superimposed next to it.

Keep those untracked files out!

Sometimes you're just a hair too quick when working with git, run a little git add -A or git add ., and then let an unwanted file or two come along for the ride. Regardless of whether it's just random scribbles or actual secrets, it's pretty annoying. And if no-one notices before you push it to the remote (or open a merge request), it could be a good few levels worse. Today I learned a way to avoid this, and I want to share it with you, dear reader.

Now, just to be clear: I don't actually recommend you blindly add all files in a directory or project to git. It's usually better to be explicit about what you're adding. Sometimes, though, it's just easier to add everything. Claiming that I've never done it or that it's never caused me grief would be disingenuous at best.

So what's the solution you ask? It's a simple flag you can pass to git add: -u or --update. Much like the flag name would suggest, this makes it add only updated files.

The docs say that this option will "/update the index just where it already has an entry matching <pathspec>. This removes as well as modifies index entries to match the working tree, *but adds no new files*/". So you can point it to a directory and it will add all changed or deleted files in that directory, but no new files.

You can also use it without a path, which will just add all deleted and modified files: "/If no <pathspec> is given when -u option is used, *all tracked files in the entire working tree are updated*/".

So next time you want to blindly add all your changes (but no new files!) to git:

git add -u

Psst! Here's a little bonus resource for ya: For more information on the behavior of git add with different options, check the answers to this stack overflow question, which is what put me on the trail of git add -u in the first place.


A mentor's thoughts

A look back at Oslo Legal Hackathon

Physical artifacts

I was a mentor at Oslo Legal Hackathon this past weekend, and while I've been to hackathons before, this was my first time participating as a mentor. I wasn't quite sure what to expect, but I felt ready.

And indeed, everything went pretty swimmingly. Well, mostly. There was a shortage of tech people, and I ended up co-mentoring a team consisting solely of people from the legal industry. Not ideal at an event that's supposed to bring legal and tech together, but they made it to the final round by focusing on the things that they could do rather than what they couldn't. But even though I think my team did a terrific job, that's not really what I want to focus on. Rather, I want to talk about the act of mentoring and how it feels different from participating.

Stepping down

Admittedly, I like being in charge. I like overseeing what's going on and giving my input on it. I often end up as team lead or in similar positions. Being a mentor is different.

Yes, I could still get an overview of where the team was headed, and yes, I could still give my input on it, but in the end, I knew that I had no real say in the matter.

I'm also very competitive. It's probably one of the main reasons that I work as hard as I do. Sure, I enjoy what I do, but I also want to be the very best. Like no one ever was.

By being slightly divorced from the process and by not actually being on the team, I could take a step back, breathe, and just enjoy seeing them work and the solutions they came up with.

In fact, I think that might be the most important thing I learned about myself: I enjoy enabling a team and seeing them succeed at least as much as I enjoy being on the team. They're two very different, yet very similar experiences.

For future reference

To close this all out, then: would I do it again? Yes. No doubt. Not only was it great fun, it was also a fantastic chance to grow my network, both within tech and within the legal industry, and to get to better know my coworkers and fellow mentors.

I've been trying to come up with some cons, but I haven't really been able to; the event was well organized, the participants and organizers were all nice people, there was food and drinks, and it was just a fun event all around.

A bit tongue-in-cheek, perhaps, but it felt great being able to come in, give feedback, express some opinions, and then go away and have someone else do the dirty work for you. I think I understand why people want to be managers now.

And finally, even if I've only been at this for a comparatively small amount of time, I felt that I really had something to contribute to the team, that I could make a difference, that I could add value. So remember: Even if you're not the most decorated or recognized individual, don't sell yourself short! As long as you invest your time and are genuinely passionate about what you do, you'll be a valuable asset to any team, no matter the role.

So don't quit, don't stop exploring new things, and don't stop making yourself uncomfortable. If you're curious, go for it!


Amending authors

Pseudonym switcheroo
The git logo with the title of the article superimposed next to it.

Alliterations abound!

If you juggle multiple git user names or emails in your job and/or spare time, it's not unlikely that you'll end up committing code with the wrong user. At a glance, there's no easy way to fix this; you can't just change the author of a commit---they're immutable, after all---but you can delete a commit and create a new one. This sounds tedious, and doing it manually is tedious, but fear not, for I am here to show you how we can do it automatically!

The trick is based on the answers to this Stack Overflow question. In short, it's just a matter of rebasing off a specific commit and then automating the process of accepting the commit as-is while changing the author.

The basics: git rebase -i

Interactively rebasing lets you choose a commit to rebase off and then choose what you want to do with all the commits since (edit, pick, delete, etc.). In this case, we want to amend the commits, so change them all to edit. If you want to leave some commits untouched, just mark them as pick.

When rebasing interactively, git will stop after each commit we've chosen to edit, saying you can amend the commit by running git commit --amend. We want to reuse the same commit message, but edit the author, and the trick for that is using the --reset-author and --no-edit options.

So far, our process looks like this:

  1. Set the right user details in our config.
      git config user.name 
      git config user.email 
  1. Initiate the rebase.
      git rebase -i 
  1. Change the commit's author and continue the rebase.
      # amend the commit, changing the author, but leaving the message intact.
      git commit --amend --reset-author --no-edit

      git rebase --continue
  1. Repeat step 3 until you're done

Tedious, but at least it works. Most likely, this doesn't happen often enough that you'll need to automate it, so we could just leave it, but where's the fun in that?

Taking it further

Let's think about what we want to do: For each commit since a specific one, we want to change the author and continue the rebase. Sounds pretty easy, right? We'll just need to figure out how many iterations we need, and we have ourselves a one-liner!

So how do we go about finding out how many commits we need to change? We could count, but git does offer a command we can use for it: git rev-list. It doesn't do much without any arguments, but with the --count flag and a commit, we can start working some magic. The --count functionality, as you might expect, counts the number of commits up until the provided hash by default, but, conveniently, it can also operate on commit ranges! (As an aside: git rev-list has a lot of interesting uses, so go read the docs if you want to know more!)

To get the number of commits since the one we're using as the rebase root (thus not changing):

    git rev-list ...HEAD

This is starting to look pretty good. If we put something together, it might look something like this, with <root> being the hash of the commit we want to rebase off:

  n=$(git rev-list --count ...HEAD);\
  git rebase -i ;\
  for i in $(seq $n);\
  do\
    git commit --amend --reset-author --no-edit;\
    git rebase --continue;\
  done

or in Fish for all you cool kids:

  set n (git rev-list --count ...HEAD);\
  git rebase -i ;\
  for i in (seq $n);\
    git commit --amend --reset-author --no-edit;\
    git rebase --continue;\
  end

Note that this is a pretty naive way to do it. As outlined in this Stack Overflow question, the number of commits you're looking at might not be what's returned by git rev-list directly. For instance, if you have multiple branches that have been merged in, you might need to add the --first-parent flag to get the desired behavior.

Special case: what about rebasing off the root of the repo?

Ah, yes; this is what I've actually had to do each time I've been amending authors. We've tackled rebasing off a repo root in a prior post, so we already know that we can pass the --root flag to git rebase. When we rebase off the root, we don't need to deal with commit hashes, so it actually becomes a bit simpler:

In bash:

  n=$(git rev-list --count HEAD);\
  git rebase -i --root;\
  for i in $(seq $n);
  do\
    git commit --amend --reset-author --no-edit;\
    git rebase --continue;\
  done

And in fish:

  set n (git rev-list --count HEAD);\
  git rebase -i --root;\
  for i in (seq $n);\
    git commit --amend --reset-author --no-edit;\
    git rebase --continue;\
  end