int git_branch_move( git_reference **out, git_reference *branch, const char *new_branch_name, int force) { git_buf new_reference_name = GIT_BUF_INIT, old_config_section = GIT_BUF_INIT, new_config_section = GIT_BUF_INIT, log_message = GIT_BUF_INIT; int error; assert(branch && new_branch_name); if (!git_reference_is_branch(branch)) return not_a_local_branch(git_reference_name(branch)); if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0) goto done; if ((error = git_buf_printf(&log_message, "branch: renamed %s to %s", git_reference_name(branch), git_buf_cstr(&new_reference_name))) < 0) goto done; /* first update ref then config so failure won't trash config */ error = git_reference_rename( out, branch, git_buf_cstr(&new_reference_name), force, git_buf_cstr(&log_message)); if (error < 0) goto done; git_buf_join(&old_config_section, '.', "branch", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)); git_buf_join(&new_config_section, '.', "branch", new_branch_name); error = git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&old_config_section), git_buf_cstr(&new_config_section)); done: git_buf_free(&new_reference_name); git_buf_free(&old_config_section); git_buf_free(&new_config_section); git_buf_free(&log_message); return error; }
static void rename_branch(const char *oldname, const char *newname, int force) { struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; unsigned char sha1[20]; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; int recovery = 0; if (!oldname) die(_("cannot rename the current branch while not on any.")); if (strbuf_check_branch_ref(&oldref, oldname)) { /* * Bad name --- this could be an attempt to rename a * ref that we used to allow to be created by accident. */ if (resolve_ref(oldref.buf, sha1, 1, NULL)) recovery = 1; else die(_("Invalid branch name: '%s'"), oldname); } validate_new_branchname(newname, &newref, force, 0); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); if (rename_ref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch rename failed")); strbuf_release(&logmsg); if (recovery) warning(_("Renamed a misnamed branch '%s' away"), oldref.buf + 11); /* no need to pass logmsg here as HEAD didn't really move */ if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL)) die(_("Branch renamed to %s, but HEAD is not updated!"), newname); strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11); strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", newref.buf + 11); strbuf_release(&newref); if (git_config_rename_section(oldsection.buf, newsection.buf) < 0) die(_("Branch is renamed, but update of config-file failed")); strbuf_release(&oldsection); strbuf_release(&newsection); }
int git_branch_move( git_reference *branch, const char *new_branch_name, int force) { git_buf new_reference_name = GIT_BUF_INIT, old_config_section = GIT_BUF_INIT, new_config_section = GIT_BUF_INIT; int error; assert(branch && new_branch_name); if (!git_reference_is_branch(branch)) return not_a_local_branch(branch); if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0) goto cleanup; if (git_buf_printf( &old_config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) goto cleanup; if ((error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force)) < 0) goto cleanup; if (git_buf_printf(&new_config_section, "branch.%s", new_branch_name) < 0) goto cleanup; if ((error = git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&old_config_section), git_buf_cstr(&new_config_section))) < 0) goto cleanup; cleanup: git_buf_free(&new_reference_name); git_buf_free(&old_config_section); git_buf_free(&new_config_section); return error; }
static void rename_branch(const char *oldname, const char *newname, int force) { struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; unsigned char sha1[20]; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; if (!oldname) die("cannot rename the current branch while not on any."); strbuf_addf(&oldref, "refs/heads/%s", oldname); if (check_ref_format(oldref.buf)) die("Invalid branch name: %s", oldref.buf); strbuf_addf(&newref, "refs/heads/%s", newname); if (check_ref_format(newref.buf)) die("Invalid branch name: %s", newref.buf); if (resolve_ref(newref.buf, sha1, 1, NULL) && !force) die("A branch named '%s' already exists.", newname); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); if (rename_ref(oldref.buf, newref.buf, logmsg.buf)) die("Branch rename failed"); strbuf_release(&logmsg); /* no need to pass logmsg here as HEAD didn't really move */ if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL)) die("Branch renamed to %s, but HEAD is not updated!", newname); strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11); strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", newref.buf + 11); strbuf_release(&newref); if (git_config_rename_section(oldsection.buf, newsection.buf) < 0) die("Branch is renamed, but update of config-file failed"); strbuf_release(&oldsection); strbuf_release(&newsection); }
int git_branch_delete(git_reference *branch) { int is_head; git_buf config_section = GIT_BUF_INIT; int error = -1; assert(branch); if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch)); return -1; } if ((is_head = git_branch_is_head(branch)) < 0) return is_head; if (is_head) { giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch)); return -1; } if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) goto on_error; if (git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0) goto on_error; if (git_reference_delete(branch) < 0) goto on_error; error = 0; on_error: git_buf_free(&config_section); return error; }
static int delete_branches(int argc, const char **argv, int force, int kinds) { struct commit *rev, *head_rev = head_rev; unsigned char sha1[20]; char *name = NULL; const char *fmt, *remote; int i; int ret = 0; struct strbuf bname = STRBUF_INIT; switch (kinds) { case REF_REMOTE_BRANCH: fmt = "refs/remotes/%s"; remote = "remote "; force = 1; break; case REF_LOCAL_BRANCH: fmt = "refs/heads/%s"; remote = ""; break; default: die("cannot use -a with -d"); } if (!force) { head_rev = lookup_commit_reference(head_sha1); if (!head_rev) die("Couldn't look up commit object for HEAD"); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { int len = strlen(argv[i]); if (interpret_nth_last_branch(argv[i], &bname) != len) strbuf_add(&bname, argv[i], len); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error("Cannot delete the branch '%s' " "which you are currently on.", bname.buf); ret = 1; continue; } free(name); name = xstrdup(mkpath(fmt, bname.buf)); if (!resolve_ref(name, sha1, 1, NULL)) { error("%sbranch '%s' not found.", remote, bname.buf); ret = 1; continue; } rev = lookup_commit_reference(sha1); if (!rev) { error("Couldn't look up commit object for '%s'", name); ret = 1; continue; } /* This checks whether the merge bases of branch and * HEAD contains branch -- which means that the HEAD * contains everything in both. */ if (!force && !in_merge_bases(rev, &head_rev, 1)) { error("The branch '%s' is not an ancestor of " "your current HEAD.\n" "If you are sure you want to delete it, " "run 'git branch -D %s'.", bname.buf, bname.buf); ret = 1; continue; } if (delete_ref(name, sha1, 0)) { error("Error deleting %sbranch '%s'", remote, bname.buf); ret = 1; } else { struct strbuf buf = STRBUF_INIT; printf("Deleted %sbranch %s (%s).\n", remote, bname.buf, find_unique_abbrev(sha1, DEFAULT_ABBREV)); strbuf_addf(&buf, "branch.%s", bname.buf); if (git_config_rename_section(buf.buf, NULL) < 0) warning("Update of config-file failed"); strbuf_release(&buf); } } free(name); return(ret); }
int cmd_config(int argc, const char **argv, const char *prefix) { int nongit = !startup_info->have_repository; char *value; config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); argc = parse_options(argc, argv, prefix, builtin_config_options, builtin_config_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (use_global_config + use_system_config + use_local_config + !!given_config_file > 1) { error("only one config file at a time."); usage_with_options(builtin_config_usage, builtin_config_options); } if (use_global_config) { char *home = getenv("HOME"); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); config_exclusive_filename = user_config; } else { die("$HOME not set"); } } else if (use_system_config) config_exclusive_filename = git_etc_gitconfig(); else if (use_local_config) config_exclusive_filename = git_pathdup("config"); else if (given_config_file) { if (!is_absolute_path(given_config_file) && prefix) config_exclusive_filename = prefix_filename(prefix, strlen(prefix), given_config_file); else config_exclusive_filename = given_config_file; } if (end_null) { term = '\0'; delim = '\n'; key_delim = '\n'; } if (HAS_MULTI_BITS(types)) { error("only one type at a time."); usage_with_options(builtin_config_usage, builtin_config_options); } if (get_color_slot) actions |= ACTION_GET_COLOR; if (get_colorbool_slot) actions |= ACTION_GET_COLORBOOL; if ((get_color_slot || get_colorbool_slot) && types) { error("--get-color and variable type are incoherent"); usage_with_options(builtin_config_usage, builtin_config_options); } if (HAS_MULTI_BITS(actions)) { error("only one action at a time."); usage_with_options(builtin_config_usage, builtin_config_options); } if (actions == 0) switch (argc) { case 1: actions = ACTION_GET; break; case 2: actions = ACTION_SET; break; case 3: actions = ACTION_SET_ALL; break; default: usage_with_options(builtin_config_usage, builtin_config_options); } if (actions == ACTION_LIST) { check_argc(argc, 0, 0); if (git_config(show_all_config, NULL) < 0) { if (config_exclusive_filename) die_errno("unable to read config file '%s'", config_exclusive_filename); else die("error processing config file(s)"); } } else if (actions == ACTION_EDIT) { check_argc(argc, 0, 0); if (!config_exclusive_filename && nongit) die("not in a git directory"); git_config(git_default_config, NULL); launch_editor(config_exclusive_filename ? config_exclusive_filename : git_path("config"), NULL, NULL); } else if (actions == ACTION_SET) { int ret; check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); ret = git_config_set(argv[0], value); if (ret == CONFIG_NOTHING_SET) error("cannot overwrite multiple values with a single value\n" " Use a regexp, --add or --set-all to change %s.", argv[0]); return ret; } else if (actions == ACTION_SET_ALL) { check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar(argv[0], value, argv[2], 0); } else if (actions == ACTION_ADD) { check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar(argv[0], value, "^$", 0); } else if (actions == ACTION_REPLACE_ALL) { check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar(argv[0], value, argv[2], 1); } else if (actions == ACTION_GET) { check_argc(argc, 1, 2); return get_value(argv[0], argv[1]); } else if (actions == ACTION_GET_ALL) { do_all = 1; check_argc(argc, 1, 2); return get_value(argv[0], argv[1]); } else if (actions == ACTION_GET_REGEXP) { show_keys = 1; use_key_regexp = 1; do_all = 1; check_argc(argc, 1, 2); return get_value(argv[0], argv[1]); } else if (actions == ACTION_UNSET) { check_argc(argc, 1, 2); if (argc == 2) return git_config_set_multivar(argv[0], NULL, argv[1], 0); else return git_config_set(argv[0], NULL); } else if (actions == ACTION_UNSET_ALL) { check_argc(argc, 1, 2); return git_config_set_multivar(argv[0], NULL, argv[1], 1); } else if (actions == ACTION_RENAME_SECTION) { int ret; check_argc(argc, 2, 2); ret = git_config_rename_section(argv[0], argv[1]); if (ret < 0) return ret; if (ret == 0) die("No such section!"); } else if (actions == ACTION_REMOVE_SECTION) { int ret; check_argc(argc, 1, 1); ret = git_config_rename_section(argv[0], NULL); if (ret < 0) return ret; if (ret == 0) die("No such section!"); } else if (actions == ACTION_GET_COLOR) { get_color(argv[0]); } else if (actions == ACTION_GET_COLORBOOL) { if (argc == 1) stdout_is_tty = git_config_bool("command line", argv[0]); else if (argc == 0) stdout_is_tty = isatty(1); return get_colorbool(argc != 0); } return 0; }
static int delete_branches(int argc, const char **argv, int force, int kinds) { struct commit *rev, *head_rev = NULL; unsigned char sha1[20]; char *name = NULL; const char *fmt, *remote; int i; int ret = 0; struct strbuf bname = STRBUF_INIT; switch (kinds) { case REF_REMOTE_BRANCH: fmt = "refs/remotes/%s"; /* TRANSLATORS: This is "remote " in "remote branch '%s' not found" */ remote = _("remote "); force = 1; break; case REF_LOCAL_BRANCH: fmt = "refs/heads/%s"; remote = ""; break; default: die(_("cannot use -a with -d")); } if (!force) { head_rev = lookup_commit_reference(head_sha1); if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { strbuf_branchname(&bname, argv[i]); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error(_("Cannot delete the branch '%s' " "which you are currently on."), bname.buf); ret = 1; continue; } free(name); name = xstrdup(mkpath(fmt, bname.buf)); if (!resolve_ref(name, sha1, 1, NULL)) { error(_("%sbranch '%s' not found."), remote, bname.buf); ret = 1; continue; } rev = lookup_commit_reference(sha1); if (!rev) { error(_("Couldn't look up commit object for '%s'"), name); ret = 1; continue; } if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) { error(_("The branch '%s' is not fully merged.\n" "If you are sure you want to delete it, " "run 'git branch -D %s'."), bname.buf, bname.buf); ret = 1; continue; } if (delete_ref(name, sha1, 0)) { error(_("Error deleting %sbranch '%s'"), remote, bname.buf); ret = 1; } else { struct strbuf buf = STRBUF_INIT; printf(_("Deleted %sbranch %s (was %s).\n"), remote, bname.buf, find_unique_abbrev(sha1, DEFAULT_ABBREV)); strbuf_addf(&buf, "branch.%s", bname.buf); if (git_config_rename_section(buf.buf, NULL) < 0) warning(_("Update of config-file failed")); strbuf_release(&buf); } } free(name); return(ret); }
static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force) { struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; const char *interpreted_oldname = NULL; const char *interpreted_newname = NULL; int recovery = 0; if (!oldname) { if (copy) die(_("cannot copy the current branch while not on any.")); else die(_("cannot rename the current branch while not on any.")); } if (strbuf_check_branch_ref(&oldref, oldname)) { /* * Bad name --- this could be an attempt to rename a * ref that we used to allow to be created by accident. */ if (ref_exists(oldref.buf)) recovery = 1; else die(_("Invalid branch name: '%s'"), oldname); } /* * A command like "git branch -M currentbranch currentbranch" cannot * cause the worktree to become inconsistent with HEAD, so allow it. */ if (!strcmp(oldname, newname)) validate_branchname(newname, &newref); else validate_new_branchname(newname, &newref, force); reject_rebase_or_bisect_branch(oldref.buf); if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) || !skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) { BUG("expected prefix missing for refs"); } if (copy) strbuf_addf(&logmsg, "Branch: copied %s to %s", oldref.buf, newref.buf); else strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); if (!copy && rename_ref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch rename failed")); if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch copy failed")); if (recovery) { if (copy) warning(_("Created a copy of a misnamed branch '%s'"), interpreted_oldname); else warning(_("Renamed a misnamed branch '%s' away"), interpreted_oldname); } if (!copy && replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch renamed to %s, but HEAD is not updated!"), newname); strbuf_release(&logmsg); strbuf_addf(&oldsection, "branch.%s", interpreted_oldname); strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", interpreted_newname); strbuf_release(&newref); if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0) die(_("Branch is renamed, but update of config-file failed")); if (copy && strcmp(oldname, newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0) die(_("Branch is copied, but update of config-file failed")); strbuf_release(&oldsection); strbuf_release(&newsection); }
int cmd_config(int argc, const char **argv, const char *prefix) { int nongit; char* value; const char *file = setup_git_directory_gently(&nongit); while (1 < argc) { if (!strcmp(argv[1], "--int")) type = T_INT; else if (!strcmp(argv[1], "--bool")) type = T_BOOL; else if (!strcmp(argv[1], "--bool-or-int")) type = T_BOOL_OR_INT; else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { if (argc != 2) usage(git_config_set_usage); if (git_config(show_all_config) < 0 && file && errno) die("unable to read config file %s: %s", file, strerror(errno)); return 0; } else if (!strcmp(argv[1], "--global")) { char *home = getenv("HOME"); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); setenv(CONFIG_ENVIRONMENT, user_config, 1); free(user_config); } else { die("$HOME not set"); } } else if (!strcmp(argv[1], "--system")) setenv(CONFIG_ENVIRONMENT, git_etc_gitconfig(), 1); else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) { if (argc < 3) usage(git_config_set_usage); if (!is_absolute_path(argv[2]) && file) file = prefix_filename(file, strlen(file), argv[2]); else file = argv[2]; setenv(CONFIG_ENVIRONMENT, file, 1); argc--; argv++; } else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) { term = '\0'; delim = '\n'; key_delim = '\n'; } else if (!strcmp(argv[1], "--rename-section")) { int ret; if (argc != 4) usage(git_config_set_usage); ret = git_config_rename_section(argv[2], argv[3]); if (ret < 0) return ret; if (ret == 0) { fprintf(stderr, "No such section!\n"); return 1; } return 0; } else if (!strcmp(argv[1], "--remove-section")) { int ret; if (argc != 3) usage(git_config_set_usage); ret = git_config_rename_section(argv[2], NULL); if (ret < 0) return ret; if (ret == 0) { fprintf(stderr, "No such section!\n"); return 1; } return 0; } else if (!strcmp(argv[1], "--get-color")) { return get_color(argc-2, argv+2); } else if (!strcmp(argv[1], "--get-colorbool")) { return get_colorbool(argc-2, argv+2); } else break; argc--; argv++; } switch (argc) { case 2: return get_value(argv[1], NULL); case 3: if (!strcmp(argv[1], "--unset")) return git_config_set(argv[2], NULL); else if (!strcmp(argv[1], "--unset-all")) return git_config_set_multivar(argv[2], NULL, NULL, 1); else if (!strcmp(argv[1], "--get")) return get_value(argv[2], NULL); else if (!strcmp(argv[1], "--get-all")) { do_all = 1; return get_value(argv[2], NULL); } else if (!strcmp(argv[1], "--get-regexp")) { show_keys = 1; use_key_regexp = 1; do_all = 1; return get_value(argv[2], NULL); } else { value = normalize_value(argv[1], argv[2]); return git_config_set(argv[1], value); } case 4: if (!strcmp(argv[1], "--unset")) return git_config_set_multivar(argv[2], NULL, argv[3], 0); else if (!strcmp(argv[1], "--unset-all")) return git_config_set_multivar(argv[2], NULL, argv[3], 1); else if (!strcmp(argv[1], "--get")) return get_value(argv[2], argv[3]); else if (!strcmp(argv[1], "--get-all")) { do_all = 1; return get_value(argv[2], argv[3]); } else if (!strcmp(argv[1], "--get-regexp")) { show_keys = 1; use_key_regexp = 1; do_all = 1; return get_value(argv[2], argv[3]); } else if (!strcmp(argv[1], "--add")) { value = normalize_value(argv[2], argv[3]); return git_config_set_multivar(argv[2], value, "^$", 0); } else if (!strcmp(argv[1], "--replace-all")) { value = normalize_value(argv[2], argv[3]); return git_config_set_multivar(argv[2], value, NULL, 1); } else { value = normalize_value(argv[1], argv[2]); return git_config_set_multivar(argv[1], value, argv[3], 0); } case 5: if (!strcmp(argv[1], "--replace-all")) { value = normalize_value(argv[2], argv[3]); return git_config_set_multivar(argv[2], value, argv[4], 1); } case 1: default: usage(git_config_set_usage); } return 0; }