New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Co-authored-by" trailer #57
Conversation
If the environment variable GIT_DUET_CO_AUTHORED_BY is set to 1, there will be a "Co-authored-by" trailer added for each co-author instead of a "Signed-off-by" trailer for the committer. This gives every contributor attribution in Github's contribution graph. Resolves git-duet#56.
Thanks for taking a crack at this @ansd ! I think what you have here is reasonable, but I'm wondering if we might be able to take this as an opportunity to simplify It would be a bit of a divergence from the current techniques the tool uses that utilize the The downsides are:
While I'm actually OK with the second one as I always viewed usage of the |
@jszwedko, thanks for your feedback. I like the idea of having the Open questions:
|
Thanks for putting together that example subcommand! That is very much along the lines of what I was thinking. With regards to your open questions:
Thanks again for engaging on this. |
@jszwedko It would be good to keep supporting the It would also be handy to keep existing functionality until use of |
Requires a prepare-commit-msg hook: #!/usr/bin/env bash exec git duet-prepare-commit-msg "$1"
@jszwedko, thanks for your answer. I gave it a try. The prepare-commit-msg hook file gets now installed when running Questions:
|
Good notes, @rafecolton, thanks for checking me. I agree that we should continue supporting the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this is looking great, thanks for all of your work on this @ansd
I think the remaining items are:
- Default
GIT_DUET_SET_GIT_USER_CONFIG
whenGIT_DUET_CO_AUTHORED_BY
is set - Think a bit more about the various configuration settings users may have had set before setting
GIT_DUET_CO_AUTHORED_BY
- Some manual testing to make sure we aren't missing any cases in the automated tests you added
As this is such a divergence from the normal workflow, I'm also thinking we could mark this feature as experimental in the README to set expectations and encourage people to report any issues they find (both bugs and usability).
Thanks again! 🎉 🎊
os.Exit(1) | ||
} | ||
if committers == nil || len(committers) == 0 { | ||
os.Exit(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be assuming GIT_DUET_CO_AUTHORED_BY
implies GIT_DUET_SET_GIT_USER_CONFIG
. I agree with this decision, but I think we'll need update to duet.Configuration
to codify this (and maybe include this in the README).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also makes me realize we'll need to consider the various paths users might take opting in to this feature, e.g.:
git solo js # without GIT_DUET_SET_GIT_USER_CONFIG, so only sets `git-duet` specific configuration
export GIT_DUET_CO_AUTHORED_BY=1
git commit -m 'test' # will not use the author set by `git solo js`
I'll think about this a bit more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is just a single path how users can opt in, namely by running git duet
with GIT_DUET_CO_AUTHORED_BY
set.
I think in your above example, it's okay that the commit doesn't set js
as author since the user didn't run git solo
with either GIT_DUET_SET_GIT_USER_CONFIG
or GIT_DUET_CO_AUTHORED_BY
(the latter implicitly setting GIT_DUET_SET_GIT_USER_CONFIG
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I'm just thinking that people might have an expectation, in my example, that GIT_DUET_CO_AUTHORED_BY
would pick up the previous git solo
even without GIT_DUET_SET_USER_CONFIG
. I'm willing to concede that it feels likely that users will set that variable and then call git duet
though.
|
||
contents := strings.TrimSpace(string(b)) | ||
if contents != "" { | ||
if hook == preCommitHook && contents != strings.TrimSpace(preCommitHook) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm concerned that this doesn't allow for future versions of git-duet
to overwrite with updated hook contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, this should be rare and I think we can address it if it comes up by including an index of previous hook contents for comparison (or hashes) so I'm OK with this as-is.
@jszwedko, concerning the remaining items:
Thank you for reviewing the code :) |
git-duet/main.go
Outdated
@@ -67,6 +67,10 @@ func main() { | |||
printNextComitter(committers) | |||
if configuration.CoAuthoredBy { | |||
installPrepareCommitMsgHook() | |||
if err = gitConfig.SetAuthor(author); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify why this is needed? It wasn't immediately apparent to me (maybe a comment here would help).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed for the case that the user runs GIT_DUET_CO_AUTHORED_BY=1 git duet
without args (author initials) and without having set GIT_DUET_SET_GIT_USER_CONFIG
in previous git duet
commands. If the above line is missing, this test will fail. I will add a comment for this.
The basic question is whether running git duet
without args (author initials) should install the hook (and set the author like above) or should it be just a "getter" like it always has been which merely prints the current author and committer?
Fantastic, thanks @ansd . I appreciate you adding the additional tests and changes. I think that, for the |
When interactively rebasing or cherry-picking, the prepare-commit-msg hook gets called. Previously, a Co-authored-by trailer has been appended. This change checks first if there is already a trailer, and if there is one, no further trailer will be added since rebasing and cherry-picking doesn't change authorship. Current drawbacks: - if the commit being rebased doesn't have a trailer, a new trailer will still be appended - git commit --amend will not append new trailers if there is already a trailer
Before this commit, "git commit --verbose" didn't append any trailers because the trailers were added after the comments and diff. The right place for the trailers block is before the start of the comments. This is easily achieved with the "git interpret-trailers" command.
@jszwedko, sure, that's a good idea. See changes above. Just to summarise: The goal for rebasing and cherry-picking is to not add any So, the only drawback for now is that a new Also, |
as part of rebasing or cherry-picking, at the very least, it checks for existing trailers, | ||
and if there is one, no new trailers will be appended. | ||
Trailers will still be appended for "git commit --amend" in which case the | ||
commitMsgSource's value is "commit". */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
git-duet-prepare-commit-msg/main.go
Outdated
err = ioutil.WriteFile(commitMsgFile, []byte(fmt.Sprintf("%s\n%s", string(commitMsg), coAuthorsTrailer)), 0644) | ||
for _, c := range committers { | ||
trailer := "Co-authored-by: " + c.Name + " <" + c.Email + ">" | ||
cmd := exec.Command("git", "interpret-trailers", "--in-place", "--trailer", trailer, commitMsgFile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL this command exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also just saw it by coincidence looking at the prepare-commit-msg.sample
file :)
git-duet-prepare-commit-msg/main.go
Outdated
} | ||
|
||
// override the default "addIfDifferentNeighbor" so that no duplicate trailers will get appended | ||
err = gitConfig.SetUnnamespacedKey("trailer.ifexists", "addIfDifferent") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think setting this un-namespaced variable here might cause some slight confusion to people already depending on a different behavior. I admit it's probably pretty rare, but what do you think, rather than setting this here, we just document that you can set this value to avoid duplicate Co-authored-by:
s for the same author?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, makes sense. I removed this part from the hook and wrote it into the README so that the user can optionally set it.
git_config.go
Outdated
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (gc *GitConfig) getKey(key string) (value string, err error) { | ||
func (gc *GitConfig) SetUnnamespacedKey(key, value string) (err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, if we decide to keep the setting of the trailer config above, I'd prefer to see that exposed as a new method that abstracts away how it is setting the value (e.g. what you have for SetInitTemplateDir
) rather than exposing this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, that would have been better! I reverted the changes to this file to the previous commit since we decide to not set trailer.ifexists
in the hook.
Hi @ansd, Thanks for your continued work on this! I really appreciate it. I left a couple of comments in-line. I really like the change to using 🎆 |
Rather than having the prepare-commit-msg hook set this variable's value to `addIfDifferent`, let the user set it manually (just in case they already depend on different behaviour).
Hi @jszwedko, thanks for your comments. I removed setting the |
README.md
Outdated
When amending a commit and the co-author has changed, a new `Co-authored-by` trailer will get appended for | ||
that co-author. In order to avoid duplicate `Co-authored-by` trailers (i.e. trailers with the same co-author), | ||
set `git config [--global] trailer.ifexists addIfDifferent` to override the default value `addIfDifferentNeighbor`. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
Looks great! Thanks again for all of your hard work @ansd . I think this is ready to merge. |
Released as 0.6.0 🎉 🎺 |
This is a proposal of how the co-authored-by trailer could be implemented. It is configurable via the
GIT_DUET_CO_AUTHORED_BY
environment variable.Basically, the last commit gets amended by appending the co-authored-by trailer for each contributor. Not sure if there are better ways to do it?