{"thread":{"id":"19316","subject":"git default behavior seems odd from a Unix command line point of view","startedAt":"2009-05-12T15:18:25Z","lastAt":"2009-05-12T20:50:39Z","messageCount":8,"participants":["Andrew Schein","Junio C Hamano","Jeff King","Daniel Barkalow"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"113642","messageId":"4e963a650905120818m70b75892gb4e052187910b9a5@mail.gmail.com","threadId":"19316","inReplyTo":null,"subject":"git default behavior seems odd from a Unix command line point of view","fromName":"Andrew Schein","fromEmail":"andrew@andrewschein.com","sentAt":"2009-05-12T15:18:25Z","receivedAt":"2009-05-12T15:18:25Z","isPatch":false,"sender":{"key":"andrew@andrewschein.com","avatar":"https://gravatar.com/avatar/3a6b3a7b6a4ae7540d031e412faf9962459c4a52f303018b5a518ac76f6ec5ba?d=mp&s=160"},"body":"Hi all -\n\nI am recently working within git after some experience with mercurial.\n I am observing what I believe to be an odd default behavior from the\nperspective of UNIX command line tools.  I thought I'd share in case\nthis hasn't occurred to git maintainers or in case somebody has\ndeveloped good workaround practices.\n\nais@ace:bio[1]$ pwd\n/home/ais/repo/nps/projects/bio\nais@ace:bio$ git status\n# On branch master\nnothing to commit (working directory clean)\nais@ace:bio[1]$ git commit -a\n# On branch master\nnothing to commit (working directory clean)\nais@ace:bio[1]$\n\n\nThe [1] in my prompt indicates the exit code of the git commands. What\nI find odd is that even with the -q option, you get this verbose\noutput.  Also, you get  a non-zero exit status (which I would expect\nonly on a failure such as presence of an unresolved conflict).  My git\nusage is to have a number of small repositories and use a shell script\nto loop over them and perform a sync with a centralized server.\nHaving all this wordy output on a \"no sync necessary\" scenario seems\ncounter the desired properties of output only when work is taking\nplace or when an error occurs.\n\nHave others developed git practices to sync a bunch or repositories\nwithout all this verbose output on a \"no change\" scenario?\n\nAndy\n\n-- \nAndrew I. Schein\nwww.andrewschein.com\n"},{"id":"113652","messageId":"7vd4ae8fls.fsf@alter.siamese.dyndns.org","threadId":"19316","inReplyTo":"4e963a650905120818m70b75892gb4e052187910b9a5@mail.gmail.com","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-05-12T16:12:47Z","receivedAt":"2009-05-12T16:12:47Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andrew Schein <andrew@andrewschein.com> writes:\n\n> ais@ace:bio$ git status\n> # On branch master\n> nothing to commit (working directory clean)\n> ais@ace:bio[1]$ git commit -a\n\nThis is merely a historical accident that you cannot change.  \"git status\"\nwas originally a dual-purpose implementation detail of \"git commit\"\ncommand to:\n\n (1) report if there is anything you can commit with its exit code; and\n\n (2) if there is something to be committed, show what will and what won't\n     be committed.\n\nFor the purpose of (1), the calling command \"commit\" was told by the user\nto make a commit, so the situation where there is nothing to commit was\nsignalled as an error.  The code conceptually looked like:\n\n\t(git-commit.sh)\n\n\tdo the preparation\n\tif git-status\n        then\n        \t# message \"there is nothing to commit\" already given\n\t\trevert the preparation\n                exit 1\n\tfi\n        really make a commit\n\nThese days, \"git commit\" has been rewritten and the logic to see if there\nis anything to commit is built-in, but people still use \"git status\"\nprimarily for purpose (2), the listing of what's committed and what's\nleft.\n\nOh, and your example is wrong.  If you are going to commit with -a, and if\nyou want to see if such a \"git commit\" has actually something to commit,\nthen you should be giving -a to status as well, like:\n\n\tgit status -a && git commit -a\n\nAlso, unless you ask explicitly, \"git commit\" will not make an empty\ncommit, so you can always omit the \"git status -a &&\" part and have \"git\ncommit\" itself do the checking.\n"},{"id":"113657","messageId":"20090512162444.GC29566@coredump.intra.peff.net","threadId":"19316","inReplyTo":"4e963a650905120818m70b75892gb4e052187910b9a5@mail.gmail.com","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-05-12T16:24:45Z","receivedAt":"2009-05-12T16:24:45Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 12, 2009 at 11:18:25AM -0400, Andrew Schein wrote:\n\n> The [1] in my prompt indicates the exit code of the git commands. What\n> I find odd is that even with the -q option, you get this verbose\n> output.  Also, you get  a non-zero exit status (which I would expect\n> only on a failure such as presence of an unresolved conflict).  My git\n> usage is to have a number of small repositories and use a shell script\n> to loop over them and perform a sync with a centralized server.\n> Having all this wordy output on a \"no sync necessary\" scenario seems\n> counter the desired properties of output only when work is taking\n> place or when an error occurs.\n> \n> Have others developed git practices to sync a bunch or repositories\n> without all this verbose output on a \"no change\" scenario?\n\nYes, I have such a script. I check:\n\n  git ls-files -m -o -d --exclude-standard --directory --no-empty-directory\n\nIf it produces any output, then there is something to commit (either a\nchange in a tracked file, or an untracked file that might need to be\nadded).\n\nI also do a fetch and check to see if we have any commits that need to\nbe merged:\n\n  git rev-list master..origin\n\nor any commits that we need to push:\n\n  git rev-list origin..master\n\n(actually, it is a bit more complicated, since \"master\" and \"origin\" are\njust convention; I actually parse the config to find the branch pairs).\n\n-Peff\n"},{"id":"113658","messageId":"4e963a650905120924j52d38c0dg577d93e913013e38@mail.gmail.com","threadId":"19316","inReplyTo":"7vd4ae8fls.fsf@alter.siamese.dyndns.org","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Andrew Schein","fromEmail":"andrew@andrewschein.com","sentAt":"2009-05-12T16:24:56Z","receivedAt":"2009-05-12T16:24:56Z","isPatch":false,"sender":{"key":"andrew@andrewschein.com","avatar":"https://gravatar.com/avatar/3a6b3a7b6a4ae7540d031e412faf9962459c4a52f303018b5a518ac76f6ec5ba?d=mp&s=160"},"body":"Hi Junio -\n\nThanks for your reply giving historical context.  The command line\nexamples I gave were intended to give examples of the output rather\nthan my own usage pattern.\n\nHere is my actual usage pattern... from a file called \"sync.sh\"\n(would love feedback on whether this is the gitly? way to solve my use\ncase):\n\n# environment set up occurs before loop, I pull before \"pushing\" in an\nattempt to prevent\n# conflicts from being left on the shared repository.\nfor dir in ./* ; do\n    if [ ! -d $dir ]      ; then continue ; fi #not a directory\n    if [ ! -e $dir/.git ] ; then continue ; fi #not a git repo\n    dir=`basename $dir`\n    echo \"syncing: $dir\"\n    set +e # commit returns an error if there is nothing to commit.\n    (cd ./$dir ; git commit -a)\n    set -e\n    (cd ./$dir ; git pull $UP \"$REPO/$dir\" master)        #pull\n    ssh $HOST \"mkdir -p $DEST_CACHE/$LOC/$dir\"  # these three lines\nhandle \"push\"\n    rsync -rl --delete ./$dir/.git -e ssh \"$DEST:$DEST_CACHE/$LOC/$dir/.git\"\n    ssh $DEST \"(cd $LOC/$dir ; /tools/bin/git pull\n$DEST_CACHE/$LOC/$dir/.git master)\"\n\ndone\n"},{"id":"113659","messageId":"20090512163403.GD29566@coredump.intra.peff.net","threadId":"19316","inReplyTo":"4e963a650905120924j52d38c0dg577d93e913013e38@mail.gmail.com","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-05-12T16:34:03Z","receivedAt":"2009-05-12T16:34:03Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 12, 2009 at 12:24:56PM -0400, Andrew Schein wrote:\n\n> # environment set up occurs before loop, I pull before \"pushing\" in an\n> attempt to prevent\n> # conflicts from being left on the shared repository.\n> for dir in ./* ; do\n>     if [ ! -d $dir ]      ; then continue ; fi #not a directory\n>     if [ ! -e $dir/.git ] ; then continue ; fi #not a git repo\n>     dir=`basename $dir`\n>     echo \"syncing: $dir\"\n>     set +e # commit returns an error if there is nothing to commit.\n>     (cd ./$dir ; git commit -a)\n>     set -e\n\nOne trick to avoid playing with \"set -e\" is just:\n\n  thing_whose_error_you_want_ignore || true\n\nBut that aside, it might be nice _not_ to ignore the result from \"commit\n-a\", since it could also be warning you that it failed to correctly\ncommit. You probably want to do:\n\n  git diff --quiet HEAD || git commit -a\n\nThat is \"either there is nothing to commit, or we succeed in committing\neverything\". That of course has a race condition between the two\ncommands, though (i.e., if you modify files in between). If you want\nsomething truly atomic, I think we would need \"git commit\" to\ndistinguish error codes between \"I had nothing to commit\" and \"an error\noccurred\" (returning \"1\" right now could mean either).\n\n>     (cd ./$dir ; git pull $UP \"$REPO/$dir\" master)        #pull\n>     ssh $HOST \"mkdir -p $DEST_CACHE/$LOC/$dir\"  # these three lines\n> handle \"push\"\n>     rsync -rl --delete ./$dir/.git -e ssh \"$DEST:$DEST_CACHE/$LOC/$dir/.git\"\n>     ssh $DEST \"(cd $LOC/$dir ; /tools/bin/git pull\n> $DEST_CACHE/$LOC/$dir/.git master)\"\n\nPushing directly should be a lot more efficient in the case of repacking\n(git will realize that the remote already has certain objects, but if\nthe filenames change, rsync will not).\n\n-Peff\n"},{"id":"113680","messageId":"alpine.LNX.2.00.0905121415000.2147@iabervon.org","threadId":"19316","inReplyTo":"4e963a650905120924j52d38c0dg577d93e913013e38@mail.gmail.com","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2009-05-12T18:26:48Z","receivedAt":"2009-05-12T18:26:48Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Tue, 12 May 2009, Andrew Schein wrote:\n\n> Hi Junio -\n> \n> Thanks for your reply giving historical context.  The command line\n> examples I gave were intended to give examples of the output rather\n> than my own usage pattern.\n> \n> Here is my actual usage pattern... from a file called \"sync.sh\"\n> (would love feedback on whether this is the gitly? way to solve my use\n> case):\n\nWhat *is* your use case? What you're doing seems nuts to me (like, you're \ngoing to send out files with this script that someone is in the middle of \neditting), but I don't know what you're trying to do.\n\n> # environment set up occurs before loop, I pull before \"pushing\" in an\n> attempt to prevent\n> # conflicts from being left on the shared repository.\n> for dir in ./* ; do\n>     if [ ! -d $dir ]      ; then continue ; fi #not a directory\n>     if [ ! -e $dir/.git ] ; then continue ; fi #not a git repo\n>     dir=`basename $dir`\n>     echo \"syncing: $dir\"\n>     set +e # commit returns an error if there is nothing to commit.\n>     (cd ./$dir ; git commit -a)\n>     set -e\n>     (cd ./$dir ; git pull $UP \"$REPO/$dir\" master)        #pull\n>     ssh $HOST \"mkdir -p $DEST_CACHE/$LOC/$dir\"  # these three lines\n> handle \"push\"\n>     rsync -rl --delete ./$dir/.git -e ssh \"$DEST:$DEST_CACHE/$LOC/$dir/.git\"\n>     ssh $DEST \"(cd $LOC/$dir ; /tools/bin/git pull\n> $DEST_CACHE/$LOC/$dir/.git master)\"\n> \n> done\n\nWhat are you trying to avoid by not using \"git push\"? Why are you \ncommitting whatever changes happen to be in working directories? Are you \nintending to be able to handle non-trivial merges?\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"113688","messageId":"4e963a650905121305s244309a5vef9eec671d1ee5e@mail.gmail.com","threadId":"19316","inReplyTo":"alpine.LNX.2.00.0905121415000.2147@iabervon.org","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Andrew Schein","fromEmail":"andrew@andrewschein.com","sentAt":"2009-05-12T20:05:47Z","receivedAt":"2009-05-12T20:05:47Z","isPatch":false,"sender":{"key":"andrew@andrewschein.com","avatar":"https://gravatar.com/avatar/3a6b3a7b6a4ae7540d031e412faf9962459c4a52f303018b5a518ac76f6ec5ba?d=mp&s=160"},"body":"> What *is* your use case? What you're doing seems nuts to me (like, you're\n> going to send out files with this script that someone is in the middle of\n> editting), but I don't know what you're trying to do.\n\nI am new to git... so my first instinct is to try to reproduce a work\nflow that I know works with mercurial setup.  It is possible that the\nconcepts don't translate correctly.  Here goes...\n\nI have a bunch of separate project-related repositories.  There are\nvery few users of the system.  Most of the time I am the only user.  I\nwant a system for syncing my local repositories to a single shared\nrepository.  For example some days I work on my laptop, and some days\nfrom my desktop.  A third \"shared/public\" repository \"on campus\"\nserves as an always available repository that anyone I collaborate\nwith can pull from.  Also it is backed up, and for this reason I\ndesignate it the \"shared\" version.  So the purpose of the sync.sh\nscript is to synchronize the personal laptop/desktop repository to the\non-campus version.\n\nSomething I have learned from using mercurial in industry is that when\nsomebody messes up a \"public repo\" with conflicts they frequently\ndon't clean up the mess.  This can be a sign that they have not\nlearned the lessons of cleanliness rather than ill intent.  Otherwise\n(and similarly) this messiness can be caused from not noticing that\nthey have left a mess.\n\nThe motivation of having a sync script that is run on each user's\nlocal repository is to decrease the likelihood of a mess.  This is\nachieved by first pulling from the common repository and resolving\nconflicts _before_ \"pushing\" (note quotations) their changes to the\ncommon repository.  There is a possibility of a race condition that\nleaves a conflict on the shared repository, however the risk is\ndiminished.\n\nFinally, I use \"push\" in quotes because actually the script uses only\nuses the pull command.  This prevents proliferation of branches on the\nshared repository.\n\nIs there a better way to achieve this in git than the sync.sh script I\nsent around?\n\nThanks,\n\nAndy\n\n-- \nAndrew I. Schein\nwww.andrewschein.com\n"},{"id":"113692","messageId":"alpine.LNX.2.00.0905121619310.2147@iabervon.org","threadId":"19316","inReplyTo":"4e963a650905121305s244309a5vef9eec671d1ee5e@mail.gmail.com","subject":"Re: git default behavior seems odd from a Unix command line point of view","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2009-05-12T20:50:39Z","receivedAt":"2009-05-12T20:50:39Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Tue, 12 May 2009, Andrew Schein wrote:\n\n> > What *is* your use case? What you're doing seems nuts to me (like, you're\n> > going to send out files with this script that someone is in the middle of\n> > editting), but I don't know what you're trying to do.\n> \n> I am new to git... so my first instinct is to try to reproduce a work\n> flow that I know works with mercurial setup.  It is possible that the\n> concepts don't translate correctly.  Here goes...\n> \n> I have a bunch of separate project-related repositories.  There are\n> very few users of the system.  Most of the time I am the only user.  I\n> want a system for syncing my local repositories to a single shared\n> repository.  For example some days I work on my laptop, and some days\n> from my desktop.  A third \"shared/public\" repository \"on campus\"\n> serves as an always available repository that anyone I collaborate\n> with can pull from.  Also it is backed up, and for this reason I\n> designate it the \"shared\" version.  So the purpose of the sync.sh\n> script is to synchronize the personal laptop/desktop repository to the\n> on-campus version.\n\nIn general, you should probably not have the script run \"commit\", but run \nit by hand whenever you've finished making changes (and probably done at \nleast a quick syntax test, if possible). Otherwise, you'll often get the \nsituation where you get distracted halfway through modifying a line, save \nsomething by habit, and then find this state getting sent to the system \nthat other people pull from, and they'll find that they can't build your \nlatest code.\n\n> Something I have learned from using mercurial in industry is that when\n> somebody messes up a \"public repo\" with conflicts they frequently\n> don't clean up the mess.  This can be a sign that they have not\n> learned the lessons of cleanliness rather than ill intent.  Otherwise\n> (and similarly) this messiness can be caused from not noticing that\n> they have left a mess.\n\nIn the normal process of pushing changes to a shared repository, there is \nno possibility of leaving conflicts, because there's no way to get git to \nattempt a merge on push; the push simply fails, and you then pull, resolve \nany conflicts, commit the merge, and try again at pushing.\n\n> The motivation of having a sync script that is run on each user's\n> local repository is to decrease the likelihood of a mess.  This is\n> achieved by first pulling from the common repository and resolving\n> conflicts _before_ \"pushing\" (note quotations) their changes to the\n> common repository.  There is a possibility of a race condition that\n> leaves a conflict on the shared repository, however the risk is\n> diminished.\n> \n> Finally, I use \"push\" in quotes because actually the script uses only\n> uses the pull command.  This prevents proliferation of branches on the\n> shared repository.\n\nIt's better to configure the push refspec to do what you want, which seems \nto be \"refs/heads/master:refs/heads/master\", and use the fact that git \npush actually does what you're trying to do in a race-free and efficient \nway.\n\nAlso, the \"refs/heads/*:refs/heads/*\" refspec is only different in the \ncase where you use branches other than \"master\", and seems like it would \nbe useful for your use case; if you actually want to send everything you \ndo to the shared location, you want to have all of the branches you've \nmade. (That is, you get one branch on the shared repository per distinct \nname of a branch that you use on a local repository, not one \"master\" for \neach local repository's \"master\")\n\n\t-Daniel\n*This .sig left intentionally blank*\n"}]}