The way all version control systems I'm familiar with work is that each commit is attributed to a single developer. The rise of Agile Engineering, and specifically pair programming, has lead to a situation where two developers have made a significant contribution to the same task, a bug fix for example.
The issue of attribution won't be too much of a big deal in a work environment since the project manager will be aware of the work the pairs are doing, but what about if two open source contributors decide to pair up and push out some code to a particular project that has no idea they're working together. Is there any way for a version control system like Git to attribute a particular patch to multiple developers?
Commit title
Commit body
Co-authored-by: name <additional-dev-1#example.com>
Co-authored-by: name <additional-dev-2#example.com>
Supported by GitHub and GitLab
Used by others: https://git.wiki.kernel.org/index.php/CommitMessageConventions
One problem with this approach is that you can't create a signed key for this group of devs, so you could essentially add anybody to this list even if they didn't work on a feature and GitHub would treat it as if they did. However, this shouldn't be an issue in most cases.
e.g. Co-authored-by: Linus Torvalds <torvalds#linux-foundation.org>
With normal authors or signing groups (the old method) you would see it's not signed and know that you can't trust the commit. However, there is no signing process on co-authors.
Mostly outdated answer:
One solution would be to set a name for the pair:
git config user.name "Chris Wilson and John Smith"
Here is a related bug report with other temporary solutions:
Bug git-core: Git should support multiple authors for a commit
A git convention is to use Co-Authored-By at the end of the commit message (git kernel: Commit Message Conventions, referring to Openstack Commit Messages). This is also one of the solutions on the git-core bug linked in Gerry's answer
Co-authored-by: Some One <some.one#example.foo>
In that comment on May 5, 2010, Josh Triplett also suggests implementing corresponding support in git.
As Llopis pointed out in a comment, GitHub announced support for this on their blog on Jan 29, 2018: Commit together with co-authors (details).
For Bazaar:
bzr commit --author Joe --author Alice --author Bob
Those names will be shown in the log separately from committer name.
git-pair
https://github.com/pivotal/git_scripts#git-pair
This simple script from Pivotal to automate Git pair programming attribution.
You create a .pairs file like:
# .pairs - configuration for 'git pair'
pairs:
# <initials>: <Firstname> <Lastname>[; <email-id>]
eh: Edward Hieatt
js: Josh Susser; jsusser
sf: Serguei Filimonov; serguei
email:
prefix: pair
domain: pivotallabs.com
# no_solo_prefix: true
#global: true
and then:
git pair sp js
sets:
user.name=Josh Susser & Sam Pierson
user.email=pair+jsusser+sam#pivotallabs.com
for you.
git distinguishes between a commit's author and committer [1]. You could use it as a work-around, e.g. sign yourself as the committer and your co-author as the author:
GIT_COMMITTER_NAME='a' GIT_COMMITTER_EMAIL='a#a' git commit --author 'b <b#b>'
This way, both you and your co-author will be recorded in the git history. Running git log --format=fuller, will give you something like:
commit 22ef837878854ca2ecda72428834fcbcad6043a2
Author: b <b#b>
AuthorDate: Tue Apr 12 06:53:41 2016 +0100
Commit: a <a#a>
CommitDate: Tue Apr 12 09:18:53 2016 +0000
Test commit.
[1] Difference between author and committer in Git?
Try git-mob, we built it for attributing co-authors on commits.
E.g.
git mob <initials of co-authors>
git commit
git solo
Alternatively, there is an open source project, which I contribute to, on GitHub that provides a good way to do it from the command line. This project helps you to set an alias in order to create co-autored commits as follows:
$ git co-commit -m "Commit message" --co "co-author <co-author-email>"
Using this approach, you are able to create co-authored commits without a graphical interface.
We add our names to each commit message at the end as a convention
eg : Implemented cool feature <Aneesh | Hiren>
Most of the co-author tools do not support autocompletion. You can try git-coco, its written in python3 (I'm the developer). git-coco supports autocomplete and auto-suggest.
Here is a snapshot
autocomplete on sample authors
Related
what I want is quite simple, I think.. (?) - We are using commitizen as commit messages formating tool.
And, using husky for git hooks.
I would like to add a hook for editing the commit messages (with nodejs), as follows:
Now, let's say someone created this commit message:
fix(prepare-commit-msg) adding ticket number as prefix to this commit from branch name
Our branch's naming convention looks something like that:
userName2424/sc-27172/and-this-is-the-ticket-title
The output for the commit I want to achieve is:
27172: fix(prepare-commit-msg) adding ticket number as prefix to this commit from branch name
Thanks in advance
I am using nodegit to checkout from clone and Open it to do something.
My code like this:
//repo is a Repository from Clone() or Open()
//branchName is your branch name, of course
repo.getBranch('refs/remotes/origin/' + branchName)
.then(function(reference) {
//checkout branch
return repo.checkoutRef(reference);
});
But after that I cd in to branch directory and typing the command like this
git status
or git branch
It's show a red line like this
HEAD detached at origin/branchname
How can I solved it?
Thanks
In general,1 origin/somebranch is not a branch name, and therefore git checkout origin/somebranch results in a detached HEAD, exactly as you are seeing.
Branch names, in Git, don't really do any good, to a first approximation.2 So there's no need to use them. To understand how and why this is the case, let's note that in Git, there are many kinds of names.
A branch name is simply a name which, when spelled out in full, begins with refs/heads/. The branch names master or main, for instance, are really refs/heads/master and refs/heads/main, correspondingly.
A tag name is a name which, when spelled out in full, begins with refs/tags/. So v2.1 is really refs/tags/v2.1.
Git calls these things—these names in general, before they're split into some particular classification—refs or references. Each reference holds one (1) hash ID. The hash ID is what really matters to Git. That's what Git needs. That's what git checkout requires: a hash ID. You can give it any valid commit hash ID, and it will check out that commit.
Hash IDs, though, are big and ugly and look random (though they're not). They are thoroughly unmemorable. What commit is 225365fb5195e804274ab569ac3cc4919451dc7f anyway? If I say v2.31.0-rc0, that probably means something—or at least, seems suggestive of something—to you; but if I say 2253blah you have probably forgotten the 2253 part long before I get to the dc7f part. So refs are for humans. They're not for Git, which only really cares about the hash IDs.
You only need a ref—such as a branch name—if you're a human. If you're a build system, a hash ID is fine. If you're writing part of a build system, just use a hash ID. If you're writing something for a human to use ... well, humans are hard.
Git has a special thing it calls "DWIM", or Do What I Mean, mode. If you run:
git checkout foobranch
and there is no branch named foobranch right now, Git will assume that you mean: Find me a name that resembles foobranch, such as origin/foobranch. Then use that name to make a branch name for me. You can disable this with git checkout --no-guess and sometimes that's a good idea. But sometimes this DWIM mode is exactly what you want.
Note, however, that if the pesky human went and made his own foobranch earlier, not related to origin/foobranch, this git checkout foobranch will get his foobranch, not related to origin/foobranch. So be careful: humans are tricky and weird. They do illogical, unexpected things.
Now, there's a reason humans often want to use a branch name, rather than any other name that results in the detached-HEAD mode. The primary reason they like this is because then, if they make a new commit, Git will change the hash ID stored in the branch name. The new commit will automatically link, backwards, to whatever commit was the one stored in the reference. Then Git will update the branch name so that it now stores the hash ID of the new commit.
This feature is exclusive to branch names. No other kind of name has this special feature. You can select detached-HEAD mode when using a branch name, by running git checkout --detach foobranch for instance. But the default is that when you use git checkout with a branch name—even one that DWIM mode is going to have to create—Git will instead go into attached HEAD mode.3 So that's why humans like branch names, and that's what Git does with them, that it doesn't do with any other reference name.
If you need to accommodate humans, you can do that by letting the DWIM mode do its thing here. That won't satisfy all humans, so watch out. It also won't work in some cases, so watch out. The detached-HEAD mode always works, though.
In NodeGit specifically, you have Branch.create as an async class method of Branch.. You also have Branch.lookup. You could use this to look up a remote-tracking name, like origin/branchname, and use that to create a new local branch, if that's your goal. But as before, watch out for all these various edge cases.
1It is possible to make a (local) branch named origin/somebranch, so that it is a branch name. The result is very confusing unless you carefully call out all names using their full spellings. Don't do this!
2Of course, they do do some good, so the first approximation is pretty rough.
3Git does not call it this, but what else could the right phrase for "opposite of detached HEAD" mode be?
Let there be:
There are different repositories repoA, repoB and repoC each respecting the same directory layout principles, which are to be merged onto a third repoM's working directory (the "master" project).
repoM has an atypical setup (--work-dir and --git-dir are sepparate). repo[A-C] are cloned as bare, and they are set as core.bare = false and core.worktree=<--work-dir-of-repoM>.
The requirements:
I need to always have an overview over the history of all files in repoM's work-dir, which could have stemmed from repo[A-C]. With this approach, I lose all that information.
Alternative:
I've been thinking about using git-subtree instead (git version 1.7.11.2, so it's already built-in), leaving repo[A-C] bare, and then
git pull -s subtree, or
git subtree ...
With the subtree pull strategy, I lose the history on a merge conflict (git blame says so).
I've never used subtree before, but from my understanding it's not possible to merge files from repo[A-C] into repoM's work-dir, those files must be put into a subdirectory of repo[A-C]. This is definitely not what I need. Why? Because of the following ...
Problem statement:
You have different git repositories each containing different sets of files, usually configuration files and some shell scripts. You want to put everything in the $HOME (which is <--work-dir-of-repoM>) directory from all those repositories. You should be able to see at all time where each file comes from, edit, commit and push changes to each one's origin. You've guessed it, it something like vundle, but generalized for any kind of configuration of any program, not just vim bundles. If a conflict occures, one should be able to track down which two authors of the same file need to get in touch with each other and make up a deal (if one needs to be made).
This is for an open-source project I'm trying to get a prototype working, so any help is highly appreciated. Also ideas about already existing projects which do this in a similar manner are highly appreciated.
Note: the "master directory" does not necessarily have to be $HOME, I've used it as a possible hint on the kind of problem this could solve.
Why not simply use Git Submodules in your "master project"?
I have very poor knowledge about git and would like to ask for help.
I have a linux(-only) application which shall only be "downloaded" (i.e. cloned) with git. On startup, the app shall ask the git "master server" (github) for whether there are updates.
Does git offer a command to check for whether there is an update (without really updating - only checking)? Furthermore, can my app read the return value of that command?
If you do not want to merge, you can just git fetch yourremote/yourbranch, the remote/branch specification usually being origin/master. You could then parse the output of the command to see if new commits are actually present. You can refer to the latest fetched commit as either yourremote/yourbranch or possibly by the symref FETCH_HEAD.
Note: I was reminded that FETCH_HEAD refers to the last branch that was fetched. Hence in general you cannot rely on git fetch yourremote with FETCH_HEAD since the former fetches all tracked branches, thus the latter may not refer to yourbranch. Additionally,
you end up fetching more than strictly necessary.
also refer to Jefromi's answer to view but not actually downloaded changes
the following are not necessarily the most compact formats, just readable examples.
That being said, here are some options for checking for updates of a remote branch, which we will denote with yourremote/yourbranch:
0. Handling errors in the following operations:
0.1 If you attempt to git fetch yourremote, and git gives you an error like
conq: repository does not exist.
that probably means you don't have that remote-string defined. Check your defined remote-strings with git remote --verbose, then git remote add yourremote yourremoteURI as needed.
0.2 If git gives you an error like
fatal: ambiguous argument 'yourremote/yourbranch': unknown revision or path not in the working tree.
that probably means you don't have yourremote/yourbranch locally. I'll leave it to someone more knowledgeable to explain what it means to have something remote locally :-) but will say here only that you should be able to fix that error with
git fetch yourremote
after which you should be able to repeat your desired command successfully. (Provided you have defined git remote yourremote correctly: see previous item.)
1. If you need detailed information, git show yourremote/yourbranch and compare it to the current git show yourbranch
2. If you only want to see the differences, git diff yourbranch yourremote/yourbranch
3. If you prefer to make comparisons on the hash only, compare git rev-parse yourremote/yourbranch to git rev-parse yourbranch
4. If you want to use the log to backtrack what happened, you can do something like git log --pretty=oneline yourremote/yourbranch...yourbranch (note use of three dots).
If you really don't want to actually use bandwidth and fetch new commits, but just check whether there is anything to fetch, you can use:
git fetch --dry-run [remote]
where [remote] defaults to origin. You'll have to parse the output, though, which looks something like this:
From git://git.kernel.org/pub/scm/git/git
2e49dab..7f41b6b master -> origin/master
so it's really much easier to just fetch everything (git fetch [remote]), and then look at the diff/log e.g. between master and [remote]/master.
I'd say git fetch is a potential solution. It only updates the index, not working code. In cases of large commit sets, this would involve a download of compressed files/info, so it may be more than you want, but it is the most useful download you can do.
is there a commend to delete project from svn with all its revisions(total cleanup) ?
cheers
The answer is in the Subversion FAQ:
There are special cases where you
might want to destroy all evidence of
a file or commit. (Perhaps somebody
accidentally committed a confidential
document.) This isn't so easy, because
Subversion is deliberately designed to
never lose information. Revisions are
immutable trees which build upon one
another. Removing a revision from
history would cause a domino effect,
creating chaos in all subsequent
revisions and possibly invalidating
all working copies.
The project has plans, however, to
someday implement an svnadmin
obliterate command which would
accomplish the task of permanently
deleting information. (See issue 516.)
In the meantime, your only recourse is
to svnadmin dump your repository, then
pipe the dumpfile through
svndumpfilter (excluding the bad path)
into an svnadmin load command. See
chapter 5 of the Subversion book for
details about this.
No, I don't believe there is.
If you really need to remove files completely from SVN history, I think the only way to do it would be to do something like dumping the repository, filtering out the files you don't want with svndumpfilter, and then recreate the repository from the dump.
Why do you want to do this?
rm -rf on the repository usually works fine.
this is how to do this on Linux:
/>svnadmin dump /path/to/repos > proj.dump
/>cat proj.dump | svndumpfilter exclude somefolder > cleanproj.dump
/>service svn stop
/>BACKUP /path/to/repos/conf /path/to/repos/hooks (all custom configuration for this repository)
/>DELETE /path/to/repos
/>svnadmin create /path/to/repos
/>RESTORE /path/to/repos/conf /path/to/repos/hooks
/>svnadmin load /path/to/repos < cleanproj.dump
/>service svn start
done
I'm assuming that you are talking about multiple projects under the same repository:
myrepo/
project1/
project2/
If you simply want a project to 'disappear' without screwing with the repository history, you can simply hide this path if you are using an authentication mechanism that utilizes authz. In other words, you are not using 'svn+ssh' to access the repository.
Let's say I already have a group in my authz called 'everyone'. The in my authz I will set something like:
[/project1]:
#everyone =